Merge remote-tracking branch 'adafruit/main' into automount_sd

This commit is contained in:
Scott Shawcroft 2025-04-01 10:30:29 -07:00
commit e8875f51c4
No known key found for this signature in database
57 changed files with 1916 additions and 213 deletions

View file

@ -5,8 +5,8 @@ runs:
steps:
- name: Get broadcom toolchain
run: |
wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz
sudo tar -C /usr --strip-components=1 -xaf gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz
wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-elf.tar.xz
sudo tar -C /usr --strip-components=1 -xaf arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-elf.tar.xz
sudo apt-get update
sudo apt-get install -y mtools
shell: bash

5
.gitignore vendored
View file

@ -97,3 +97,8 @@ TAGS
# clangd cache
##############
.cache
**/CLAUDE.local.md
# windsurf rules
.windsurfrules

View file

@ -189,4 +189,18 @@ This feature is not enabled on boards that the CIRCUITPY_OS_GETENV (os CIRCUIPTY
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
~~~~~~~~~~~~~~~~~~~~~~~
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.
This feature requires both CIRCUITPY_OS_GETENV and CIRCUITPY_LVFONTIO to be enabled.
Example:
.. code-block::
CIRCUITPY_TERMINAL_FONT="/fonts/myfont.lvfontbin"
`boards that the terminalio core module is available on <https://docs.circuitpython.org/en/latest/shared-bindings/terminalio/>`_

View file

@ -1076,7 +1076,7 @@ msgstr "Gagal menulis flash internal."
msgid "File exists"
msgstr "File sudah ada"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr ""
@ -1272,6 +1272,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr ""
@ -2010,6 +2011,7 @@ msgstr "Potongan dan nilai panjangnya berbeda."
#: 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 "Potongan tidak didukung"
@ -2080,7 +2082,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "Tinggi tile harus persis membagi tinggi bitmap"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "Indeks ubin di luar batas"
@ -4326,7 +4330,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 ""

View file

@ -1051,7 +1051,7 @@ msgstr ""
msgid "File exists"
msgstr ""
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr ""
@ -1247,6 +1247,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr ""
@ -4280,7 +4281,7 @@ msgstr ""
msgid "unreadable attribute"
msgstr ""
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-bindings/vectorio/VectorShape.c
msgid "unsupported %q type"

View file

@ -1069,7 +1069,7 @@ msgstr "Nepodařilo se zapsat do interní paměti."
msgid "File exists"
msgstr "soubor existuje"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "Soubor nenalezen"
@ -1267,6 +1267,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "Špatný %s"
@ -1998,6 +1999,7 @@ msgstr ""
#: 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 ""
@ -2065,7 +2067,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr ""
@ -4306,7 +4310,9 @@ msgstr "neshoduje se '%c' ve formátu"
msgid "unreadable attribute"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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"

View file

@ -1076,7 +1076,7 @@ msgstr "Interner Flash konnte nicht geschrieben werden."
msgid "File exists"
msgstr "Datei existiert"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "Datei nicht gefunden"
@ -1278,6 +1278,7 @@ msgstr "Unterbrochen durch Ausgabefunktion"
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "Ungültiger %q"
@ -2018,6 +2019,7 @@ msgstr "Slice und Wert (value) haben unterschiedliche Längen."
#: 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 "Slices werden nicht unterstützt"
@ -2090,7 +2092,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "Die Kachelhöhe muss die Bitmaphöhe genau teilen"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "Kachelindex außerhalb der Grenzen"
@ -4366,7 +4370,9 @@ msgstr "'%c' in Format konnte nicht zugeordnet werden"
msgid "unreadable attribute"
msgstr "nicht lesbares Attribut"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "Nicht unterstützter %q-Typ"

View file

@ -1077,7 +1077,7 @@ msgstr ""
msgid "File exists"
msgstr ""
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr ""
@ -1273,6 +1273,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr ""
@ -2003,6 +2004,7 @@ msgstr ""
#: 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 ""
@ -2070,7 +2072,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr ""
@ -4305,7 +4309,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 ""

View file

@ -1069,7 +1069,7 @@ msgstr "Failed to write internal flash."
msgid "File exists"
msgstr "File exists"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "File not found"
@ -1266,6 +1266,7 @@ msgstr "Interrupted by output function"
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "Invalid %q"
@ -1999,6 +2000,7 @@ msgstr "Slice and value different lengths."
#: 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 "Slices not supported"
@ -2068,7 +2070,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "Tile height must exactly divide bitmap height"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "Tile index out of bounds"
@ -4313,7 +4317,9 @@ msgstr "unmatched '%c' in format"
msgid "unreadable attribute"
msgstr "unreadable attribute"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "unsupported %q type"

View file

@ -1080,7 +1080,7 @@ msgstr "Error al escribir el flash interno."
msgid "File exists"
msgstr "El archivo ya existe"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "Archivo no encontrado"
@ -1288,6 +1288,7 @@ msgstr "Interrumpido por resultado de función"
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "%q inválido"
@ -2029,6 +2030,7 @@ msgstr "Slice y value tienen tamaños diferentes."
#: 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 "Rebanadas no soportadas"
@ -2099,7 +2101,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "La altura del Tile debe dividir exacto la altura del bitmap"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "Índice de mosaico fuera de límites"
@ -4360,7 +4364,9 @@ msgstr "no coteja '%c' en formato"
msgid "unreadable attribute"
msgstr "atributo no legible"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "tipo de %q no soportado"

View file

@ -1063,7 +1063,7 @@ msgstr ""
msgid "File exists"
msgstr "Mayroong file"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr ""
@ -1259,6 +1259,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr ""
@ -1992,6 +1993,7 @@ msgstr "Slice at value ay iba iba ang haba."
#: 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 "Hindi suportado ang Slices"
@ -2059,7 +2061,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr ""
@ -4309,7 +4313,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr "hindi mabasa ang attribute"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "Hindi supportadong tipo ng %q"

View file

@ -1090,7 +1090,7 @@ msgstr "Échec de l'écriture vers flash interne."
msgid "File exists"
msgstr "Le fichier existe"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "Fichier non trouvé"
@ -1294,6 +1294,7 @@ msgstr "Interrompu par la fonction de sortie"
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "%q invalide"
@ -2040,6 +2041,7 @@ msgstr "Tranche et valeur de tailles différentes."
#: 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 "Tranches non supportées"
@ -2110,7 +2112,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "La hauteur de la tuile doit diviser exactement la hauteur de l'image"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "Index des tuiles hors limites"
@ -4382,7 +4386,9 @@ msgstr "'%c' sans correspondance dans le format"
msgid "unreadable attribute"
msgstr "attribut illisible"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "type %q non pris on charge"

View file

@ -1053,7 +1053,7 @@ msgstr ""
msgid "File exists"
msgstr ""
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr ""
@ -1249,6 +1249,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr ""
@ -1977,6 +1978,7 @@ msgstr ""
#: 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 ""
@ -2044,7 +2046,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr ""
@ -4279,7 +4283,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 ""

View file

@ -1061,7 +1061,7 @@ msgstr ""
msgid "File exists"
msgstr "File esistente"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr ""
@ -1257,6 +1257,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr ""
@ -1990,6 +1991,7 @@ msgstr ""
#: 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 "Slice non supportate"
@ -2057,7 +2059,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr ""
@ -4311,7 +4315,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr "attributo non leggibile"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "tipo di %q non supportato"

View file

@ -1070,7 +1070,7 @@ msgstr "内部フラッシュ書き込みに失敗"
msgid "File exists"
msgstr "ファイルが存在します"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr ""
@ -1266,6 +1266,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "不正な %q"
@ -1999,6 +2000,7 @@ msgstr "スライスと値の長さが一致しません"
#: 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 "スライスは対応していません"
@ -2066,7 +2068,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "タイルの高さはビットマップの高さを割り切れる値でなければなりません"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "タイルのインデクスが範囲外"
@ -4307,7 +4311,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr "読み込み不可能な属性"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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"

View file

@ -1103,7 +1103,7 @@ msgstr "내부 플래시를 쓰는 것에 실패했습니다."
msgid "File exists"
msgstr "파일이 있습니다"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "파일을 찾을 수 없습니다"
@ -1301,6 +1301,7 @@ msgstr "출력 함수로 인해 종료되었다"
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "잘못된 %q"
@ -2052,6 +2053,7 @@ msgstr ""
#: 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 ""
@ -2119,7 +2121,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr ""
@ -4355,7 +4359,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 ""

View file

@ -1056,7 +1056,7 @@ msgstr "Schrijven naar interne flash mislukt."
msgid "File exists"
msgstr "Bestand bestaat"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr ""
@ -1252,6 +1252,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "Ongeldige %q"
@ -1989,6 +1990,7 @@ msgstr "Slice en waarde hebben verschillende lengtes."
#: 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 "Slices niet ondersteund"
@ -2056,7 +2058,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "Tile hoogte moet exact de bitmap hoogte verdelen"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "Tile index buiten bereik"
@ -4301,7 +4305,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr "onleesbaar attribuut"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "niet ondersteund %q type"

View file

@ -1069,7 +1069,7 @@ msgstr "Nie udało się zapisać wewnętrznej pamięci flash."
msgid "File exists"
msgstr "Plik istnieje"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "Plik nie znaleziony"
@ -1271,6 +1271,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "Nieprawidłowe %q"
@ -2003,6 +2004,7 @@ msgstr "Fragment i wartość są różnych długości."
#: 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 "Fragmenty nieobsługiwane"
@ -2070,7 +2072,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "Wysokość bitmapy musi być wielokrotnością wysokości kafelka"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr ""
@ -4309,7 +4313,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr "nieczytelny atrybut"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "zły typ %q"

View file

@ -1080,7 +1080,7 @@ msgstr "Falha ao gravar o flash interno."
msgid "File exists"
msgstr "Arquivo já existe"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "Arquivo não encontrado"
@ -1285,6 +1285,7 @@ msgstr "Interrompido pela função de saída"
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "%q Inválido"
@ -2031,6 +2032,7 @@ msgstr "Fatie e avalie os diferentes comprimentos."
#: 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 "Fatiamento não compatível"
@ -2101,7 +2103,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "A altura do bloco deve dividir exatamente com a altura do bitmap"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "O índice do bloco está fora dos limites"
@ -4374,7 +4378,9 @@ msgstr "'%c' sem correspondência no formato"
msgid "unreadable attribute"
msgstr "atributo ilegível"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "tipo %q não suportado"

View file

@ -1082,7 +1082,7 @@ msgstr "Не удалось записать внутреннюю флэш-па
msgid "File exists"
msgstr "Файл существует"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "Файл не найден"
@ -1288,6 +1288,7 @@ msgstr "Прерывается функцией выхода"
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "Недопустимый %q"
@ -2028,6 +2029,7 @@ msgstr "Нарежьте и оцените разную длину."
#: 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 "Фрагменты не поддерживаются"
@ -2100,7 +2102,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "Высота плитки должна точно делить высоту растрового изображения"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "Выход индекса плитки за пределы"
@ -4370,7 +4374,9 @@ msgstr "Несовпадающий '%c' в формате"
msgid "unreadable attribute"
msgstr "Нечитаемый атрибут"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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"

View file

@ -1074,7 +1074,7 @@ msgstr "Det gick inte att skriva till intern flash."
msgid "File exists"
msgstr "Filen finns redan"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "Filen hittades inte"
@ -1274,6 +1274,7 @@ msgstr "Avbruten av utgångsfunktion"
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "Ogiltig %q"
@ -2010,6 +2011,7 @@ msgstr "Slice och värde har olika längd."
#: 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 "Slice stöds inte"
@ -2079,7 +2081,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "Tile-höjden måste vara jämnt delbar med höjd på bitmap"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "Tile-index utanför gräns"
@ -4328,7 +4332,9 @@ msgstr "Omatchad '%c' i format"
msgid "unreadable attribute"
msgstr "attribut kan inte läsas"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "typ %q stöds inte"

View file

@ -1067,7 +1067,7 @@ msgstr "Dahili flaş yazılamadı."
msgid "File exists"
msgstr "Dosya var"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr ""
@ -1267,6 +1267,7 @@ msgstr ""
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "Geçersiz %q"
@ -1999,6 +2000,7 @@ msgstr ""
#: 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 ""
@ -2066,7 +2068,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr ""
@ -4301,7 +4305,9 @@ msgstr ""
msgid "unreadable attribute"
msgstr ""
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 ""

View file

@ -1075,7 +1075,7 @@ msgstr "Wúfǎ xiě rù nèibù shǎncún."
msgid "File exists"
msgstr "Wénjiàn cúnzài"
#: shared-module/os/getenv.c
#: shared-module/lvfontio/OnDiskFont.c shared-module/os/getenv.c
msgid "File not found"
msgstr "zhǎo bú dào wén jiàn"
@ -1280,6 +1280,7 @@ msgstr "bèi shūchū gōngnéng zhōngduàn"
#: shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c
#: shared-module/aurora_epaper/aurora_framebuffer.c
#: shared-module/lvfontio/OnDiskFont.c
msgid "Invalid %q"
msgstr "wú xiào %q"
@ -2017,6 +2018,7 @@ msgstr "Qiēpiàn hé zhí bùtóng chángdù."
#: 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 "Qiēpiàn bù shòu zhīchí"
@ -2086,7 +2088,9 @@ msgstr ""
msgid "Tile height must exactly divide bitmap height"
msgstr "Píng pū gāodù bìxū huàfēn wèi tú gāodù"
#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c
#: shared-bindings/displayio/TileGrid.c
#: shared-bindings/tilepalettemapper/TilePaletteMapper.c
#: shared-module/displayio/TileGrid.c
msgid "Tile index out of bounds"
msgstr "Píng pū zhǐshù chāochū fànwéi"
@ -4338,7 +4342,9 @@ msgstr "gé shì bù pǐ pèi de '%c'"
msgid "unreadable attribute"
msgstr "bùkě dú shǔxìng"
#: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c
#: 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 "bù zhīchí %q lèixíng"

View file

@ -12,6 +12,7 @@ CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 1
CIRCUITPY_LTO = 1
CIRCUITPY_KEYPAD_DEMUX ?= 0
CIRCUITPY_LVFONTIO ?= 0
######################################################################
# Put samd21-only choices here.

View file

@ -74,11 +74,11 @@ static bool picodvi_autoconstruct_enabled(mp_int_t *default_width, mp_int_t *def
if ((established_timings & 0x80) != 0 &&
preferred_width % 1920 == 0 &&
preferred_height % 1080 == 0) {
*default_width = 720 / 2;
*default_height = 400 / 2;
*default_width = 720;
*default_height = 400;
} else {
*default_width = 640 / 2;
*default_height = 480 / 2;
*default_width = 640;
*default_height = 480;
}
}
}
@ -95,15 +95,15 @@ void picodvi_autoconstruct(void) {
return;
}
mp_int_t default_width = 320;
mp_int_t default_height = 240;
mp_int_t default_width = 640;
mp_int_t default_height = 480;
if (!picodvi_autoconstruct_enabled(&default_width, &default_height)) {
return;
}
mp_int_t width = default_width;
mp_int_t height = 0;
mp_int_t color_depth = 16;
mp_int_t color_depth = 8;
mp_int_t rotation = 0;
(void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_WIDTH", &width);
@ -113,6 +113,9 @@ void picodvi_autoconstruct(void) {
if (height == 0) {
switch (width) {
case 720:
height = 400;
break;
case 640:
height = 480;
break;
@ -134,7 +137,7 @@ void picodvi_autoconstruct(void) {
// invalid configuration, set back to default
width = default_width;
height = default_height;
color_depth = 16;
color_depth = 8;
}
// construct framebuffer and display

View file

@ -27,6 +27,8 @@ CIRCUITPY_BITMAPFILTER = 0
CIRCUITPY_BITMAPTOOLS = 0
CIRCUITPY_BLEIO_HCI = 0
CIRCUITPY_EPAPERDISPLAY = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_I2CDISPLAYBUS = 0
CIRCUITPY_KEYPAD_DEMUX = 0
CIRCUITPY_SHARPDISPLAY = 0
CIRCUITPY_TILEPALETTEMAPPER = 0

View file

@ -9,6 +9,8 @@ MCU_SERIES = F4
MCU_VARIANT = STM32F411xE
MCU_PACKAGE = LQFP100_f4
OPTIMIZATION_FLAGS = -Os
LD_COMMON = boards/common_default.ld
LD_FILE = boards/STM32F411_fs.ld

View file

@ -13,6 +13,8 @@ MCU_SERIES = F4
MCU_VARIANT = STM32F411xE
MCU_PACKAGE = UFQFPN48
OPTIMIZATION_FLAGS = -Os
LD_COMMON = boards/common_nvm.ld
LD_FILE = boards/STM32F411_nvm.ld

View file

@ -25,11 +25,7 @@ MCU_SERIES = F4
MCU_VARIANT = STM32F411xE
MCU_PACKAGE = UFQFPN48
OPTIMIZATION_FLAGS = -Os
LD_COMMON = boards/common_nvm.ld
LD_FILE = boards/STM32F411_nvm_nofs.ld
# Disable TERMINALIO on translations with missing characters.
ifneq (,$(filter $(TRANSLATION),ja ko ru))
CIRCUITPY_TERMINALIO = 0
RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO)
endif

View file

@ -58,6 +58,7 @@ jpegio = false
keypad = false
keypad_demux = false
locale = false
lvfontio = false
math = false
max3421e = false
mdns = false

View file

@ -58,6 +58,7 @@ jpegio = false
keypad = false
keypad_demux = false
locale = false
lvfontio = false
math = false
max3421e = false
mdns = false

View file

@ -58,6 +58,7 @@ jpegio = false
keypad = false
keypad_demux = false
locale = false
lvfontio = false
math = false
max3421e = false
mdns = false

View file

@ -58,6 +58,7 @@ jpegio = false
keypad = false
keypad_demux = false
locale = false
lvfontio = false
math = false
max3421e = false
mdns = false

View file

@ -58,6 +58,7 @@ jpegio = false
keypad = false
keypad_demux = false
locale = false
lvfontio = false
math = false
max3421e = false
mdns = false

View file

@ -58,6 +58,7 @@ jpegio = false
keypad = false
keypad_demux = false
locale = false
lvfontio = false
math = false
max3421e = false
mdns = false

View file

@ -58,6 +58,7 @@ jpegio = false
keypad = false
keypad_demux = false
locale = false
lvfontio = false
math = false
max3421e = false
mdns = false

View file

@ -0,0 +1,101 @@
#!/usr/bin/env python3
import pathlib
import sys
import tomlkit
def find_modules(top_dir, port_dir):
"""Find all available modules in shared-bindings and port bindings."""
modules = set()
for module in sorted(
list(top_dir.glob("shared-bindings/*")) + list(port_dir.glob("bindings/*")),
key=lambda x: x.name,
):
if not module.is_dir():
continue
modules.add(module.name)
return sorted(modules)
def find_board_info_files(port_dir):
"""Find all autogen_board_info.toml files in the port directory."""
return list(port_dir.glob("boards/**/autogen_board_info.toml"))
def update_board_info(board_info_path, available_modules):
"""Update board info file with new modules set to false."""
if not board_info_path.exists():
print(f"Error: Board info file {board_info_path} does not exist", file=sys.stderr)
return False
# Load existing board info
with open(board_info_path, "r", encoding="utf-8") as f:
board_info = tomlkit.load(f)
# Get current modules
current_modules = set(board_info.get("modules", {}))
# Find new modules
new_modules = set(available_modules) - current_modules
if not new_modules:
print(
f"No new modules found for {board_info_path.relative_to(board_info_path.parents[3])}"
)
return True
# Add new modules as disabled in alphabetical order
modules_table = board_info["modules"]
# Get all modules (existing and new) and sort them
all_modules = list(current_modules | new_modules)
all_modules.sort()
# Create a new table with sorted modules
sorted_table = tomlkit.table()
for module in all_modules:
if module in modules_table:
# TODO: Use modules_table.item once tomlkit is released with changes from January 2025
sorted_table[module] = modules_table._value.item(module)
else:
sorted_table[module] = tomlkit.item(False)
# Replace the modules table with the sorted one
board_info["modules"] = sorted_table
# Write updated board info
with open(board_info_path, "w", encoding="utf-8") as f:
tomlkit.dump(board_info, f)
print(
f"Updated {board_info_path.relative_to(board_info_path.parents[3])} with {len(new_modules)} new modules:"
)
for module in sorted(new_modules):
print(f" - {module}")
return True
def main():
# Get repo paths
script_dir = pathlib.Path(__file__).parent
top_dir = script_dir.parents[2] # circuitpython root
port_dir = script_dir.parent # zephyr-cp directory
# Get available modules once
available_modules = find_modules(top_dir, port_dir)
# Update all board info files
board_info_files = find_board_info_files(port_dir)
if not board_info_files:
print("No board info files found")
sys.exit(1)
success = True
for board_info_path in board_info_files:
if not update_board_info(board_info_path, available_modules):
success = False
sys.exit(0 if success else 1)
if __name__ == "__main__":
main()

View file

@ -396,6 +396,9 @@ endif
ifeq ($(CIRCUITPY_FONTIO),1)
SRC_PATTERNS += fontio/%
endif
ifeq ($(CIRCUITPY_LVFONTIO),1)
SRC_PATTERNS += lvfontio/%
endif
ifeq ($(CIRCUITPY_TILEPALETTEMAPPER),1)
SRC_PATTERNS += tilepalettemapper/%
endif
@ -675,6 +678,8 @@ SRC_SHARED_MODULE_ALL = \
floppyio/__init__.c \
fontio/BuiltinFont.c \
fontio/__init__.c \
lvfontio/OnDiskFont.c\
lvfontio/__init__.c \
fourwire/__init__.c \
fourwire/FourWire.c \
framebufferio/FramebufferDisplay.c \

View file

@ -555,9 +555,12 @@ CFLAGS += -DCIRCUITPY_TERMINALIO=$(CIRCUITPY_TERMINALIO)
CIRCUITPY_TERMINALIO_VT100 ?= $(CIRCUITPY_TERMINALIO)
CFLAGS += -DCIRCUITPY_TERMINALIO_VT100=$(CIRCUITPY_TERMINALIO_VT100)
CIRCUITPY_FONTIO ?= $(call enable-if-all,$(CIRCUITPY_DISPLAYIO) $(CIRCUITPY_TERMINALIO))
CIRCUITPY_FONTIO ?= $(CIRCUITPY_TERMINALIO)
CFLAGS += -DCIRCUITPY_FONTIO=$(CIRCUITPY_FONTIO)
CIRCUITPY_LVFONTIO ?= $(CIRCUITPY_TERMINALIO)
CFLAGS += -DCIRCUITPY_LVFONTIO=$(CIRCUITPY_LVFONTIO)
CIRCUITPY_TILEPALETTEMAPPER ?= $(CIRCUITPY_DISPLAYIO)
CFLAGS += -DCIRCUITPY_TILEPALETTEMAPPER=$(CIRCUITPY_TILEPALETTEMAPPER)

View file

@ -62,7 +62,8 @@ void displayio_tilegrid_validate_pixel_shader(mp_obj_t pixel_shader) {
//| convert the value and its location to a display native pixel color. This may be a simple color
//| palette lookup, a gradient, a pattern or a color transformer.
//|
//| To save RAM usage, tile values are only allowed in the range from 0 to 255 inclusive (single byte values).
//| When the total number of tiles is 256 or less, tile values are stored as single bytes (uint8_t).
//| When the total number of tiles is more than 256, tile values are stored as double bytes (uint16_t).
//|
//| tile_width and tile_height match the height of the bitmap by default.
//|
@ -453,7 +454,7 @@ static mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v
return MP_OBJ_NULL; // op not supported
} else {
mp_int_t value = mp_obj_get_int(value_obj);
mp_arg_validate_int_range(value, 0, 255, MP_QSTR_tile);
mp_arg_validate_int_range(value, 0, self->tiles_in_bitmap - 1, MP_QSTR_tile);
common_hal_displayio_tilegrid_set_tile(self, x, y, value);
}

View file

@ -13,7 +13,7 @@ extern const mp_obj_type_t displayio_tilegrid_type;
void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles,
mp_obj_t pixel_shader, uint16_t width, uint16_t height,
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile);
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint16_t default_tile);
bool common_hal_displayio_tilegrid_get_hidden(displayio_tilegrid_t *self);
void common_hal_displayio_tilegrid_set_hidden(displayio_tilegrid_t *self, bool hidden);
@ -43,9 +43,9 @@ uint16_t common_hal_displayio_tilegrid_get_height(displayio_tilegrid_t *self);
uint16_t common_hal_displayio_tilegrid_get_tile_width(displayio_tilegrid_t *self);
uint16_t common_hal_displayio_tilegrid_get_tile_height(displayio_tilegrid_t *self);
uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y);
void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index);
uint16_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y);
void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint16_t tile_index);
// Private API for scrolling the TileGrid.
void common_hal_displayio_tilegrid_set_top_left(displayio_tilegrid_t *self, uint16_t x, uint16_t y);
void common_hal_displayio_tilegrid_set_all_tiles(displayio_tilegrid_t *self, uint8_t tile_index);
void common_hal_displayio_tilegrid_set_all_tiles(displayio_tilegrid_t *self, uint16_t tile_index);

View file

@ -0,0 +1,94 @@
// 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/lvfontio/OnDiskFont.h"
#include <stdint.h>
#include "shared/runtime/context_manager_helpers.h"
#include "py/binary.h"
#include "py/objproperty.h"
#include "py/objstr.h"
#include "py/runtime.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/util.h"
//| class OnDiskFont:
//| """A font built into CircuitPython for use with LVGL"""
//|
//| def __init__(self, file_path: str, max_glyphs: int = 100) -> None:
//| """Create a OnDiskFont by loading an LVGL font file from the filesystem.
//|
//| :param str file_path: The path to the font file
//| :param int max_glyphs: Maximum number of glyphs to cache at once
//| """
//| ...
//|
//| bitmap: displayio.Bitmap
//| """Bitmap containing all font glyphs starting with ASCII and followed by unicode. This is useful for use with LVGL."""
//|
static mp_obj_t lvfontio_ondiskfont_obj_get_bitmap(mp_obj_t self_in) {
lvfontio_ondiskfont_t *self = MP_OBJ_TO_PTR(self_in);
return common_hal_lvfontio_ondiskfont_get_bitmap(self);
}
MP_DEFINE_CONST_FUN_OBJ_1(lvfontio_ondiskfont_get_bitmap_obj, lvfontio_ondiskfont_obj_get_bitmap);
MP_PROPERTY_GETTER(lvfontio_ondiskfont_bitmap_obj,
(mp_obj_t)&lvfontio_ondiskfont_get_bitmap_obj);
//| def get_bounding_box(self) -> Tuple[int, int]:
//| """Returns the maximum bounds of all glyphs in the font in a tuple of two values: width, height."""
//| ...
//|
//|
static mp_obj_t lvfontio_ondiskfont_obj_get_bounding_box(mp_obj_t self_in) {
lvfontio_ondiskfont_t *self = MP_OBJ_TO_PTR(self_in);
return common_hal_lvfontio_ondiskfont_get_bounding_box(self);
}
MP_DEFINE_CONST_FUN_OBJ_1(lvfontio_ondiskfont_get_bounding_box_obj, lvfontio_ondiskfont_obj_get_bounding_box);
static const mp_rom_map_elem_t lvfontio_ondiskfont_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&lvfontio_ondiskfont_bitmap_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_bounding_box), MP_ROM_PTR(&lvfontio_ondiskfont_get_bounding_box_obj) },
};
static MP_DEFINE_CONST_DICT(lvfontio_ondiskfont_locals_dict, lvfontio_ondiskfont_locals_dict_table);
static mp_obj_t lvfontio_ondiskfont_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_path, ARG_max_glyphs };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_file_path, MP_ARG_OBJ | MP_ARG_REQUIRED },
{ MP_QSTR_max_glyphs, MP_ARG_INT, {.u_int = 100} },
};
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);
// Allocate the BuiltinFont object
lvfontio_ondiskfont_t *self = m_new_obj(lvfontio_ondiskfont_t);
self->base.type = &lvfontio_ondiskfont_type;
// Extract arguments
mp_obj_t file_path_obj = args[ARG_file_path].u_obj;
mp_uint_t max_glyphs = args[ARG_max_glyphs].u_int;
// Get the C string from the Python string
const char *file_path = mp_obj_str_get_str(file_path_obj);
// Always use GC allocator for Python-created objects
common_hal_lvfontio_ondiskfont_construct(self, file_path, max_glyphs, true);
return MP_OBJ_FROM_PTR(self);
}
MP_DEFINE_CONST_OBJ_TYPE(
lvfontio_ondiskfont_type,
MP_QSTR_OnDiskFont,
MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS,
make_new, lvfontio_ondiskfont_make_new,
locals_dict, &lvfontio_ondiskfont_locals_dict
);

View file

@ -0,0 +1,22 @@
// 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
#include "shared-module/lvfontio/OnDiskFont.h"
extern const mp_obj_type_t lvfontio_ondiskfont_type;
mp_obj_t common_hal_lvfontio_ondiskfont_get_bitmap(const lvfontio_ondiskfont_t *self);
mp_obj_t common_hal_lvfontio_ondiskfont_get_bounding_box(const lvfontio_ondiskfont_t *self);
void common_hal_lvfontio_ondiskfont_get_dimensions(const lvfontio_ondiskfont_t *self, uint16_t *width, uint16_t *height);
// Function prototypes
void common_hal_lvfontio_ondiskfont_construct(lvfontio_ondiskfont_t *self, const char *file_path, uint16_t max_glyphs, bool use_gc_allocator);
void common_hal_lvfontio_ondiskfont_deinit(lvfontio_ondiskfont_t *self);
bool common_hal_lvfontio_ondiskfont_deinited(lvfontio_ondiskfont_t *self);
int16_t common_hal_lvfontio_ondiskfont_cache_glyph(lvfontio_ondiskfont_t *self, uint32_t codepoint, bool *is_full_width);
void common_hal_lvfontio_ondiskfont_release_glyph(lvfontio_ondiskfont_t *self, uint32_t slot);

View file

@ -0,0 +1,33 @@
// 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 <stdint.h>
#include "py/obj.h"
#include "py/runtime.h"
#include "shared-bindings/lvfontio/__init__.h"
#include "shared-bindings/lvfontio/OnDiskFont.h"
//| """Core font related data structures for LVGL
//|
//| .. note:: This module is intended only for low-level usage with LVGL.
//|
//| """
static const mp_rom_map_elem_t lvfontio_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_lvfontio) },
{ MP_ROM_QSTR(MP_QSTR_OnDiskFont), MP_ROM_PTR(&lvfontio_ondiskfont_type) },
};
static MP_DEFINE_CONST_DICT(lvfontio_module_globals, lvfontio_module_globals_table);
const mp_obj_module_t lvfontio_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&lvfontio_module_globals,
};
MP_REGISTER_MODULE(MP_QSTR_lvfontio, lvfontio_module);

View file

@ -0,0 +1,7 @@
// 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

View file

@ -16,6 +16,10 @@
#include "py/stream.h"
#include "shared-bindings/fontio/BuiltinFont.h"
#if CIRCUITPY_LVFONTIO
#include "shared-bindings/lvfontio/OnDiskFont.h"
#endif
//| class Terminal:
//| """Display a character stream with a TileGrid
//|
@ -86,7 +90,26 @@ static mp_obj_t terminalio_terminal_make_new(const mp_obj_type_t *type, size_t n
status_bar = mp_arg_validate_type(args[ARG_status_bar].u_obj, &displayio_tilegrid_type, MP_QSTR_status_bar);
}
fontio_builtinfont_t *font = mp_arg_validate_type(args[ARG_font].u_obj, &fontio_builtinfont_type, MP_QSTR_font);
mp_obj_t font = args[ARG_font].u_obj;
// Ensure the font is one of the supported types
bool valid_font = false;
#if CIRCUITPY_FONTIO
if (mp_obj_is_type(font, &fontio_builtinfont_type)) {
valid_font = true;
}
#endif
#if CIRCUITPY_LVFONTIO
if (mp_obj_is_type(font, &lvfontio_ondiskfont_type)) {
valid_font = true;
}
#endif
if (!valid_font) {
mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported %q type"), MP_QSTR_font);
}
mp_arg_validate_int_min(scroll_area->width_in_tiles, 2, MP_QSTR_scroll_area_width);
mp_arg_validate_int_min(scroll_area->height_in_tiles, 2, MP_QSTR_scroll_area_height);

View file

@ -13,7 +13,7 @@
extern const mp_obj_type_t terminalio_terminal_type;
extern void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self,
displayio_tilegrid_t *scroll_area, const fontio_builtinfont_t *font, displayio_tilegrid_t *status_bar);
displayio_tilegrid_t *scroll_area, mp_obj_t font, displayio_tilegrid_t *status_bar);
// Write characters. len is in characters NOT bytes!
extern size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self,

View file

@ -15,29 +15,53 @@
#include "shared-bindings/tilepalettemapper/TilePaletteMapper.h"
#endif
#include "supervisor/shared/serial.h"
void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles,
mp_obj_t pixel_shader, uint16_t width, uint16_t height,
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile) {
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint16_t default_tile) {
uint32_t total_tiles = width * height;
self->bitmap_width_in_tiles = bitmap_width_in_tiles;
self->tiles_in_bitmap = bitmap_width_in_tiles * bitmap_height_in_tiles;
// Determine if we need uint16_t or uint8_t for tile indices
bool use_uint16 = self->tiles_in_bitmap > 255;
// Sprites will only have one tile so save a little memory by inlining values in the pointer.
uint8_t inline_tiles = sizeof(uint8_t *);
uint8_t inline_tiles = sizeof(void *) / (use_uint16 ? sizeof(uint16_t) : sizeof(uint8_t));
if (total_tiles <= inline_tiles) {
self->tiles = 0;
// Pack values into the pointer since there are only a few.
for (uint32_t i = 0; i < inline_tiles; i++) {
((uint8_t *)&self->tiles)[i] = default_tile;
if (use_uint16) {
for (uint32_t i = 0; i < inline_tiles && i < total_tiles; i++) {
((uint16_t *)&self->tiles)[i] = default_tile;
}
} else {
for (uint32_t i = 0; i < inline_tiles && i < total_tiles; i++) {
((uint8_t *)&self->tiles)[i] = (uint8_t)default_tile;
}
}
self->inline_tiles = true;
} else {
self->tiles = (uint8_t *)m_malloc(total_tiles);
for (uint32_t i = 0; i < total_tiles; i++) {
self->tiles[i] = default_tile;
if (use_uint16) {
uint16_t *tiles16 = (uint16_t *)m_malloc(total_tiles * sizeof(uint16_t));
for (uint32_t i = 0; i < total_tiles; i++) {
tiles16[i] = default_tile;
}
self->tiles = tiles16;
} else {
uint8_t *tiles8 = (uint8_t *)m_malloc(total_tiles);
for (uint32_t i = 0; i < total_tiles; i++) {
tiles8[i] = (uint8_t)default_tile;
}
self->tiles = tiles8;
}
self->inline_tiles = false;
}
self->bitmap_width_in_tiles = bitmap_width_in_tiles;
self->tiles_in_bitmap = bitmap_width_in_tiles * bitmap_height_in_tiles;
self->width_in_tiles = width;
self->height_in_tiles = height;
self->x = x;
@ -234,29 +258,42 @@ uint16_t common_hal_displayio_tilegrid_get_tile_height(displayio_tilegrid_t *sel
return self->tile_height;
}
uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y) {
uint8_t *tiles = self->tiles;
uint16_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y) {
void *tiles = self->tiles;
if (self->inline_tiles) {
tiles = (uint8_t *)&self->tiles;
tiles = &self->tiles;
}
if (tiles == NULL) {
return 0;
}
return tiles[y * self->width_in_tiles + x];
uint32_t index = y * self->width_in_tiles + x;
if (self->tiles_in_bitmap > 255) {
return ((uint16_t *)tiles)[index];
} else {
return ((uint8_t *)tiles)[index];
}
}
void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index) {
void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint16_t tile_index) {
if (tile_index >= self->tiles_in_bitmap) {
mp_raise_ValueError(MP_ERROR_TEXT("Tile index out of bounds"));
}
uint8_t *tiles = self->tiles;
void *tiles = self->tiles;
if (self->inline_tiles) {
tiles = (uint8_t *)&self->tiles;
tiles = &self->tiles;
}
if (tiles == NULL) {
return;
}
tiles[y * self->width_in_tiles + x] = tile_index;
uint32_t index = y * self->width_in_tiles + x;
if (self->tiles_in_bitmap > 255) {
((uint16_t *)tiles)[index] = tile_index;
} else {
((uint8_t *)tiles)[index] = (uint8_t)tile_index;
}
displayio_area_t temp_area;
displayio_area_t *tile_area;
if (!self->partial_change) {
@ -284,21 +321,32 @@ void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t
self->partial_change = true;
}
void common_hal_displayio_tilegrid_set_all_tiles(displayio_tilegrid_t *self, uint8_t tile_index) {
void common_hal_displayio_tilegrid_set_all_tiles(displayio_tilegrid_t *self, uint16_t tile_index) {
if (tile_index >= self->tiles_in_bitmap) {
mp_raise_ValueError(MP_ERROR_TEXT("Tile index out of bounds"));
}
uint8_t *tiles = self->tiles;
void *tiles = self->tiles;
if (self->inline_tiles) {
tiles = (uint8_t *)&self->tiles;
tiles = &self->tiles;
}
if (tiles == NULL) {
return;
}
for (uint16_t x = 0; x < self->width_in_tiles; x++) {
if (self->tiles_in_bitmap > 255) {
uint16_t *tiles16 = (uint16_t *)tiles;
for (uint16_t y = 0; y < self->height_in_tiles; y++) {
tiles[y * self->width_in_tiles + x] = tile_index;
for (uint16_t x = 0; x < self->width_in_tiles; x++) {
tiles16[y * self->width_in_tiles + x] = tile_index;
}
}
} else {
uint8_t *tiles8 = (uint8_t *)tiles;
for (uint16_t y = 0; y < self->height_in_tiles; y++) {
for (uint16_t x = 0; x < self->width_in_tiles; x++) {
tiles8[y * self->width_in_tiles + x] = (uint8_t)tile_index;
}
}
}
@ -368,9 +416,9 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self,
const _displayio_colorspace_t *colorspace, const displayio_area_t *area,
uint32_t *mask, uint32_t *buffer) {
// If no tiles are present we have no impact.
uint8_t *tiles = self->tiles;
void *tiles = self->tiles;
if (self->inline_tiles) {
tiles = (uint8_t *)&self->tiles;
tiles = &self->tiles;
}
if (tiles == NULL) {
return false;
@ -474,7 +522,12 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self,
uint16_t x_tile_index = (local_x / self->tile_width + self->top_left_x) % self->width_in_tiles;
uint16_t y_tile_index = (local_y / self->tile_height + self->top_left_y) % self->height_in_tiles;
uint16_t tile_location = y_tile_index * self->width_in_tiles + x_tile_index;
input_pixel.tile = tiles[tile_location];
if (self->tiles_in_bitmap > 255) {
input_pixel.tile = ((uint16_t *)tiles)[tile_location];
} else {
input_pixel.tile = ((uint8_t *)tiles)[tile_location];
}
input_pixel.tile_x = (input_pixel.tile % self->bitmap_width_in_tiles) * self->tile_width + local_x % self->tile_width;
input_pixel.tile_y = (input_pixel.tile / self->bitmap_width_in_tiles) * self->tile_height + local_y % self->tile_height;

View file

@ -30,7 +30,7 @@ typedef struct {
uint16_t tile_height;
uint16_t top_left_x;
uint16_t top_left_y;
uint8_t *tiles;
void *tiles; // Can be either uint8_t* or uint16_t* depending on tiles_in_bitmap
const displayio_buffer_transform_t *absolute_transform;
displayio_area_t dirty_area; // Stored as a relative area until the refresh area is fetched.
displayio_area_t previous_area; // Stored as an absolute area.

View file

@ -0,0 +1,843 @@
// 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 <string.h>
#include "shared-bindings/lvfontio/OnDiskFont.h"
#include "py/runtime.h"
#include "py/mperrno.h"
#include "py/stream.h"
#include "py/objstr.h"
#include "py/gc.h"
#include "shared-bindings/displayio/Bitmap.h"
#include "extmod/vfs_fat.h"
#include "lib/oofatfs/ff.h"
#include "supervisor/shared/translate/translate.h"
#include "supervisor/port.h"
#include "supervisor/shared/serial.h"
#include "supervisor/filesystem.h"
// Helper functions for memory allocation
static inline void *allocate_memory(lvfontio_ondiskfont_t *self, size_t size) {
void *ptr;
if (self->use_gc_allocator) {
ptr = m_malloc_maybe(size);
} else {
ptr = port_malloc(size, false);
}
if (ptr != NULL) {
return ptr;
}
common_hal_lvfontio_ondiskfont_deinit(self);
if (self->use_gc_allocator) {
m_malloc_fail(size);
}
return NULL;
}
static inline void free_memory(lvfontio_ondiskfont_t *self, void *ptr) {
if (self->use_gc_allocator) {
m_free(ptr);
} else {
port_free(ptr);
}
}
// Forward declarations for helper functions
static int16_t find_codepoint_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint);
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);
// Load font header data from file
static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max_slots) {
UINT bytes_read;
FRESULT res;
// Start at the beginning of the file
res = f_lseek(file, 0);
if (res != FR_OK) {
return false;
}
uint8_t buffer[8];
bool found_head = false;
bool found_cmap = false;
bool found_loca = false;
bool found_glyf = false;
size_t current_position = 0;
// Read sections until we find all the sections we need or reach end of file
while (true) {
// Read section size (4 bytes)
res = f_read(file, buffer, 4, &bytes_read);
if (res != FR_OK || bytes_read < 4) {
break; // Read error or end of file
}
uint32_t section_size = buffer[0] | (buffer[1] << 8) |
(buffer[2] << 16) | (buffer[3] << 24);
if (section_size == 0) {
break; // End of sections marker
}
// Read section marker (4 bytes)
res = f_read(file, buffer, 4, &bytes_read);
if (res != FR_OK || bytes_read < 4) {
break; // Read error or unexpected end of file
}
// Make a null-terminated copy of the section marker for debug printing
char section_marker[5] = {0};
memcpy(section_marker, buffer, 4);
// Process different section types
if (memcmp(buffer, "head", 4) == 0) {
// Read head section data (35 bytes)
uint8_t head_buf[35];
res = f_read(file, head_buf, 35, &bytes_read);
if (res != FR_OK || bytes_read < 35) {
break;
}
// Skip version (4 bytes) and padding (1 byte)
// Parse font metrics at offset 6
self->header.font_size = head_buf[6] | (head_buf[7] << 8);
self->header.ascent = head_buf[8] | (head_buf[9] << 8);
self->header.default_advance_width = head_buf[22] | (head_buf[23] << 8);
// Parse format information
self->header.index_to_loc_format = head_buf[26];
self->header.bits_per_pixel = head_buf[29];
self->header.glyph_bbox_xy_bits = head_buf[30];
self->header.glyph_bbox_wh_bits = head_buf[31];
self->header.glyph_advance_bits = head_buf[32];
// Calculate derived values
self->header.glyph_header_bits = self->header.glyph_advance_bits +
2 * self->header.glyph_bbox_xy_bits +
2 * self->header.glyph_bbox_wh_bits;
self->header.glyph_header_bytes = (self->header.glyph_header_bits + 7) / 8;
found_head = true;
} else if (memcmp(buffer, "cmap", 4) == 0) {
// Read subtable count
uint8_t cmap_header[4];
res = f_read(file, cmap_header, 4, &bytes_read);
if (res != FR_OK || bytes_read < 4) {
break;
}
uint32_t subtable_count = cmap_header[0] | (cmap_header[1] << 8) |
(cmap_header[2] << 16) | (cmap_header[3] << 24);
// Allocate memory for cmap ranges
self->cmap_range_count = subtable_count;
self->cmap_ranges = allocate_memory(self, sizeof(lvfontio_cmap_range_t) * subtable_count);
if (self->cmap_ranges == NULL) {
return false;
}
// Read each subtable
for (uint16_t i = 0; i < subtable_count; i++) {
uint8_t subtable_buf[16];
res = f_read(file, subtable_buf, 16, &bytes_read);
if (res != FR_OK || bytes_read < 16) {
break;
}
// Read data_offset (4 bytes)
uint32_t data_offset = subtable_buf[0] | (subtable_buf[1] << 8) |
(subtable_buf[2] << 16) | (subtable_buf[3] << 24);
// Read range_start, range_length, glyph_offset
uint32_t range_start = subtable_buf[4] | (subtable_buf[5] << 8) |
(subtable_buf[6] << 16) | (subtable_buf[7] << 24);
uint16_t range_length = subtable_buf[8] | (subtable_buf[9] << 8);
uint16_t glyph_offset = subtable_buf[10] | (subtable_buf[11] << 8);
uint16_t entries_count = subtable_buf[12] | (subtable_buf[13] << 8);
// Get format type (0=sparse mapping, 1=range mapping, 2=range to range, 3=direct mapping)
uint8_t format_type = subtable_buf[14];
// Check for supported format types (0, 2, and 3)
if (format_type != 0 && format_type != 2 && format_type != 3) {
continue;
}
// Store the range information
self->cmap_ranges[i].range_start = range_start;
self->cmap_ranges[i].range_end = range_start + range_length;
self->cmap_ranges[i].glyph_offset = glyph_offset;
self->cmap_ranges[i].format_type = format_type;
self->cmap_ranges[i].data_offset = current_position + data_offset;
self->cmap_ranges[i].entries_count = entries_count;
}
found_cmap = true;
} else if (memcmp(buffer, "loca", 4) == 0) {
// Read max_cid
uint8_t loca_header[4];
res = f_read(file, loca_header, 4, &bytes_read);
if (res != FR_OK || bytes_read < 4) {
break;
}
// Store max_cid value
self->max_cid = loca_header[0] | (loca_header[1] << 8) |
(loca_header[2] << 16) | (loca_header[3] << 24);
// Store location of the loca table offset data
self->loca_table_offset = current_position + 12;
found_loca = true;
} else if (memcmp(buffer, "glyf", 4) == 0) {
// Store start of glyf table
self->glyf_table_offset = current_position;
size_t advances[2] = {0, 0};
size_t advance_count[2] = {0, 0};
if (self->header.default_advance_width != 0) {
advances[0] = self->header.default_advance_width;
}
// Set the default advance width based on the first character in the
// file.
size_t cid = 0;
while (cid < self->max_cid - 1) {
// Read glyph header fields
uint32_t glyph_advance;
int32_t bbox_x, bbox_y;
uint32_t bbox_w, bbox_h;
uint8_t byte_val = 0;
uint8_t remaining_bits = 0;
// Use the helper function to read glyph dimensions
read_glyph_dimensions(file, self, &glyph_advance, &bbox_x, &bbox_y, &bbox_w, &bbox_h, &byte_val, &remaining_bits);
// 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;
}
cid++;
}
if (self->header.default_advance_width == 0) {
if (advance_count[1] == 0) {
self->header.default_advance_width = advances[0];
*max_slots = advance_count[0];
} else {
if (advances[0] > advances[1]) {
self->header.default_advance_width = advances[0] / 2;
*max_slots = advance_count[0] * 2 + advance_count[1];
} else {
self->header.default_advance_width = advances[1] / 2;
*max_slots = advance_count[1] * 2 + advance_count[0];
}
}
}
found_glyf = true;
}
current_position += section_size;
// Skip to the end of the section
res = f_lseek(file, current_position);
if (res != FR_OK) {
break;
}
// If we found all needed sections, we can stop
if (found_head && found_cmap && found_loca && found_glyf) {
break;
}
}
// Check if we found all required sections
if (!found_head || !found_cmap || !found_loca || !found_glyf) {
return false;
}
return true;
}
// Get character ID (glyph index) for a codepoint
static int32_t get_char_id(lvfontio_ondiskfont_t *self, uint32_t codepoint) {
// Find codepoint in cmap ranges
for (uint16_t i = 0; i < self->cmap_range_count; i++) {
// Check if codepoint is in range for this subtable
if (codepoint >= self->cmap_ranges[i].range_start &&
codepoint < self->cmap_ranges[i].range_end) {
// Handle according to format type
switch (self->cmap_ranges[i].format_type) {
case 0: { // Sparse mapping - need to look up in a sparse table
if (!self->file_is_open) {
return -1;
}
// Calculate the relative position within the range
uint32_t idx = codepoint - self->cmap_ranges[i].range_start;
if (idx >= self->cmap_ranges[i].entries_count) {
return -1;
}
// Calculate the absolute data position in the file
uint32_t data_pos = self->cmap_ranges[i].data_offset + idx; // 1 byte per entry
FRESULT res = f_lseek(&self->file, data_pos);
if (res != FR_OK) {
return -1;
}
// Read the glyph ID (1 byte)
uint8_t glyph_id;
UINT bytes_read;
res = f_read(&self->file, &glyph_id, 1, &bytes_read);
if (res != FR_OK || bytes_read < 1) {
return -1;
}
return self->cmap_ranges[i].glyph_offset + glyph_id;
}
case 2: // Range to range - calculate based on offset within range
uint16_t idx = codepoint - self->cmap_ranges[i].range_start;
uint16_t glyph_id = self->cmap_ranges[i].glyph_offset + idx;
return glyph_id;
case 3: { // Direct mapping - need to look up in the table
if (!self->file_is_open) {
return -1;
}
FRESULT res;
res = f_lseek(&self->file, self->cmap_ranges[i].data_offset);
if (res != FR_OK) {
return -1;
}
uint16_t codepoint_delta = codepoint - self->cmap_ranges[i].range_start;
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) {
return -1;
}
if (candidate_codepoint_delta == codepoint_delta) {
return self->cmap_ranges[i].glyph_offset + j;
}
}
return -1;
}
default:
return -1;
}
}
}
return -1; // Not found
}
// Load glyph bitmap data into a slot
// This function assumes the file is already open and positioned after reading the glyph dimensions
static bool load_glyph_bitmap(FIL *file, lvfontio_ondiskfont_t *self, uint32_t codepoint, uint16_t slot,
uint32_t glyph_advance, int32_t bbox_x, int32_t bbox_y, uint32_t bbox_w, uint32_t bbox_h,
uint8_t *byte_val, uint8_t *remaining_bits) {
// Store codepoint at slot
self->codepoints[slot] = codepoint;
self->reference_counts[slot] = 1;
// Read bitmap data pixel by pixel
uint16_t x_offset = slot * self->header.default_advance_width;
uint16_t y_offset = self->header.ascent - bbox_y - bbox_h;
for (uint16_t y = 0; y < bbox_h; y++) {
for (uint16_t x = 0; x < bbox_w; x++) {
uint32_t pixel_value;
FRESULT res = read_bits(file, self->header.bits_per_pixel, byte_val, remaining_bits, &pixel_value);
if (res != FR_OK) {
return false;
}
// Adjust for bbox position within the glyph bounding box
int16_t bitmap_x = x_offset + x + bbox_x;
int16_t bitmap_y = y_offset + y;
// Make sure we're in bounds
if (bitmap_x >= 0 &&
bitmap_x < self->header.default_advance_width * self->max_glyphs &&
bitmap_y >= 0 &&
bitmap_y < self->header.font_size) {
common_hal_displayio_bitmap_set_pixel(
self->bitmap,
bitmap_x,
bitmap_y,
pixel_value
);
}
}
}
return true;
}
// Constructor
void common_hal_lvfontio_ondiskfont_construct(lvfontio_ondiskfont_t *self,
const char *file_path,
uint16_t max_glyphs,
bool use_gc_allocator) {
// Store the allocation mode
self->use_gc_allocator = use_gc_allocator;
// Store parameters
self->file_path = file_path; // Store the provided path string directly
self->max_glyphs = max_glyphs;
self->cmap_ranges = NULL;
self->file_is_open = false;
// Determine which filesystem to use based on the path
const char *path_under_mount;
fs_user_mount_t *vfs = filesystem_for_path(file_path, &path_under_mount);
if (vfs == NULL) {
if (self->use_gc_allocator) {
mp_raise_ValueError(MP_ERROR_TEXT("File not found"));
}
return;
}
// Open the file and keep it open for the lifetime of the object
FRESULT res = f_open(&vfs->fatfs, &self->file, path_under_mount, FA_READ);
if (res != FR_OK) {
if (self->use_gc_allocator) {
mp_raise_ValueError(MP_ERROR_TEXT("File not found"));
}
return;
}
self->file_is_open = true;
// Load font headers
size_t max_slots;
if (!load_font_header(self, &self->file, &max_slots)) {
f_close(&self->file);
self->file_is_open = false;
if (self->use_gc_allocator) {
mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_file);
}
return;
}
// Cap the number of slots to the number of slots needed by the font. That way
// small font files don't need a bunch of extra cache space.
max_glyphs = MIN(max_glyphs, max_slots);
// Allocate codepoints array. allocate_memory will raise an exception if
// allocation fails and the VM is active.
self->codepoints = allocate_memory(self, sizeof(uint32_t) * max_glyphs);
if (self->codepoints == NULL) {
return;
}
// Initialize codepoints to invalid
for (uint16_t i = 0; i < max_glyphs; i++) {
self->codepoints[i] = LVFONTIO_INVALID_CODEPOINT;
}
// Allocate reference counts
self->reference_counts = allocate_memory(self, sizeof(uint16_t) * max_glyphs);
if (self->reference_counts == NULL) {
return;
}
// Initialize reference counts to 0
memset(self->reference_counts, 0, sizeof(uint16_t) * max_glyphs);
self->half_width_px = self->header.default_advance_width;
// Create bitmap for glyph cache
displayio_bitmap_t *bitmap = allocate_memory(self, sizeof(displayio_bitmap_t));
bitmap->base.type = &displayio_bitmap_type;
if (bitmap == NULL) {
return;
}
// Calculate bitmap stride
uint32_t bits_per_pixel = 1 << self->header.bits_per_pixel;
uint32_t width = self->header.default_advance_width * max_glyphs;
uint32_t row_width = width * bits_per_pixel;
uint16_t stride = (row_width + 31) / 32; // Align to uint32_t (32 bits)
// Allocate buffer for bitmap data
uint32_t buffer_size = stride * self->header.font_size * sizeof(uint32_t);
uint32_t *bitmap_buffer = allocate_memory(self, buffer_size);
if (bitmap_buffer == NULL) {
return;
}
// Zero out bitmap buffer
memset(bitmap_buffer, 0, buffer_size);
// Construct bitmap with allocated buffer
common_hal_displayio_bitmap_construct_from_buffer(bitmap,
self->header.default_advance_width * max_glyphs,
self->header.font_size,
1 << self->header.bits_per_pixel,
bitmap_buffer,
false);
self->bitmap = bitmap;
}
void common_hal_lvfontio_ondiskfont_deinit(lvfontio_ondiskfont_t *self) {
if (!self->file_is_open) {
return;
}
if (self->bitmap != NULL) {
common_hal_displayio_bitmap_deinit(self->bitmap);
self->bitmap = NULL;
}
if (self->codepoints != NULL) {
free_memory(self, self->codepoints);
self->codepoints = NULL;
}
if (self->reference_counts != NULL) {
free_memory(self, self->reference_counts);
self->reference_counts = NULL;
}
if (self->cmap_ranges != NULL) {
free_memory(self, self->cmap_ranges);
self->cmap_ranges = NULL;
}
f_close(&self->file);
self->file_is_open = false;
}
bool common_hal_lvfontio_ondiskfont_deinited(lvfontio_ondiskfont_t *self) {
return !self->file_is_open;
}
mp_obj_t common_hal_lvfontio_ondiskfont_get_bitmap(const lvfontio_ondiskfont_t *self) {
return MP_OBJ_FROM_PTR(self->bitmap);
}
mp_obj_t common_hal_lvfontio_ondiskfont_get_bounding_box(const lvfontio_ondiskfont_t *self) {
mp_obj_t bbox[2];
bbox[0] = MP_OBJ_NEW_SMALL_INT(self->header.default_advance_width);
bbox[1] = MP_OBJ_NEW_SMALL_INT(self->header.font_size);
return mp_obj_new_tuple(2, bbox);
}
void common_hal_lvfontio_ondiskfont_get_dimensions(const lvfontio_ondiskfont_t *self,
uint16_t *width, uint16_t *height) {
if (width != NULL) {
*width = self->header.default_advance_width;
}
if (height != NULL) {
*height = self->header.font_size;
}
}
int16_t common_hal_lvfontio_ondiskfont_cache_glyph(lvfontio_ondiskfont_t *self, uint32_t codepoint, bool *is_full_width) {
// Check if already cached
int16_t existing_slot = find_codepoint_slot(self, codepoint);
if (existing_slot >= 0) {
// Glyph is already cached, increment reference count
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
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;
}
}
return existing_slot;
}
// First check if the glyph is full-width before allocating slots
// This way we know if we need one or two slots before committing
bool is_full_width_glyph = false;
// Check if file is already open
if (!self->file_is_open) {
return -1;
}
// Find character ID from codepoint
int32_t char_id = get_char_id(self, codepoint);
if (char_id < 0 || (uint32_t)char_id >= self->max_cid) {
return -1; // Invalid character
}
// Get glyph offset from location table
uint32_t glyph_offset = 0;
uint32_t loca_offset = self->loca_table_offset + char_id *
(self->header.index_to_loc_format == 1 ? 4 : 2);
FRESULT res = f_lseek(&self->file, loca_offset);
if (res != FR_OK) {
return -1;
}
UINT bytes_read;
if (self->header.index_to_loc_format == 1) {
// 4-byte offset
uint8_t offset_buf[4];
res = f_read(&self->file, offset_buf, 4, &bytes_read);
if (res != FR_OK || bytes_read < 4) {
return -1;
}
glyph_offset = offset_buf[0] | (offset_buf[1] << 8) |
(offset_buf[2] << 16) | (offset_buf[3] << 24);
} else {
// 2-byte offset
uint8_t offset_buf[2];
res = f_read(&self->file, offset_buf, 2, &bytes_read);
if (res != FR_OK || bytes_read < 2) {
return -1;
}
glyph_offset = offset_buf[0] | (offset_buf[1] << 8);
}
// Seek to glyph data
res = f_lseek(&self->file, self->glyf_table_offset + glyph_offset);
if (res != FR_OK) {
return -1;
}
// Read glyph header fields to determine width
uint32_t glyph_advance;
int32_t bbox_x, bbox_y;
uint32_t bbox_w, bbox_h;
// Initialize bit reading state
uint8_t byte_val = 0;
uint8_t remaining_bits = 0;
// Use the helper function to read glyph dimensions
res = read_glyph_dimensions(&self->file, self, &glyph_advance, &bbox_x, &bbox_y, &bbox_w, &bbox_h, &byte_val, &remaining_bits);
if (res != FR_OK) {
return -1;
}
// Check if the glyph is full-width based on its advance width
// Full-width characters typically have an advance width close to or greater than the font height
is_full_width_glyph = glyph_advance > self->half_width_px;
// Now we know if we need one or two slots
uint16_t slots_needed = is_full_width_glyph ? 2 : 1;
// Find an appropriate slot (or consecutive slots for full-width)
uint16_t slot = UINT16_MAX;
if (slots_needed == 1) {
// For regular width, find a free slot starting at codepoint's position
slot = find_free_slot(self, codepoint);
} else {
// For full-width, find two consecutive free slots
for (uint16_t i = 0; i < self->max_glyphs - 1; i++) {
if (self->codepoints[i] == LVFONTIO_INVALID_CODEPOINT &&
self->reference_counts[i] == 0 &&
self->codepoints[i + 1] == LVFONTIO_INVALID_CODEPOINT &&
self->reference_counts[i + 1] == 0) {
slot = i;
break;
}
}
}
// Check if we found appropriate slot(s)
if (slot == UINT16_MAX) {
return -1; // No slots available
}
// Load glyph into the slot
if (!load_glyph_bitmap(&self->file, self, codepoint, slot, glyph_advance,
bbox_x, bbox_y, bbox_w, bbox_h, &byte_val, &remaining_bits)) {
return -1; // Failed to load glyph
}
// For full-width characters, mark both slots with the same codepoint
if (is_full_width_glyph && slot + 1 < self->max_glyphs) {
self->codepoints[slot + 1] = codepoint;
self->reference_counts[slot + 1] = 1;
}
if (is_full_width != NULL) {
*is_full_width = is_full_width_glyph;
}
return slot;
}
void common_hal_lvfontio_ondiskfont_release_glyph(lvfontio_ondiskfont_t *self, uint32_t slot) {
if (slot >= self->max_glyphs) {
return;
}
if (self->reference_counts[slot] > 0) {
self->reference_counts[slot]--;
}
}
static int16_t find_codepoint_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint) {
size_t offset = codepoint % self->max_glyphs;
for (uint16_t i = 0; i < self->max_glyphs; i++) {
int16_t slot = (i + offset) % self->max_glyphs;
if (self->codepoints[slot] == codepoint) {
return slot;
}
}
return -1;
}
static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint) {
size_t offset = codepoint % self->max_glyphs;
// First look for completely unused slots, starting at the offset
for (uint16_t i = 0; i < self->max_glyphs; i++) {
int16_t slot = (i + offset) % self->max_glyphs;
if (self->codepoints[slot] == LVFONTIO_INVALID_CODEPOINT && self->reference_counts[slot] == 0) {
return slot;
}
}
// If none found, look for slots with zero reference count, starting at the offset
for (uint16_t i = 0; i < self->max_glyphs; i++) {
int16_t slot = (i + offset) % self->max_glyphs;
if (self->reference_counts[slot] == 0) {
return slot;
}
}
// No slots available
return UINT16_MAX;
}
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) {
FRESULT res;
uint32_t temp_value;
// Read glyph_advance
res = read_bits(file, self->header.glyph_advance_bits, byte_val, remaining_bits, &temp_value);
if (res != FR_OK) {
return res;
}
*advance_width = temp_value;
// Read bbox_x (signed)
res = read_bits(file, self->header.glyph_bbox_xy_bits, byte_val, remaining_bits, &temp_value);
if (res != FR_OK) {
return res;
}
// Convert to signed value if needed
if (temp_value & (1 << (self->header.glyph_bbox_xy_bits - 1))) {
*bbox_x = temp_value - (1 << self->header.glyph_bbox_xy_bits);
} else {
*bbox_x = temp_value;
}
// Read bbox_y (signed)
res = read_bits(file, self->header.glyph_bbox_xy_bits, byte_val, remaining_bits, &temp_value);
if (res != FR_OK) {
return res;
}
// Convert to signed value if needed
if (temp_value & (1 << (self->header.glyph_bbox_xy_bits - 1))) {
*bbox_y = temp_value - (1 << self->header.glyph_bbox_xy_bits);
} else {
*bbox_y = temp_value;
}
// Read bbox_w
res = read_bits(file, self->header.glyph_bbox_wh_bits, byte_val, remaining_bits, &temp_value);
if (res != FR_OK) {
return res;
}
*bbox_w = temp_value;
// Read bbox_h
res = read_bits(file, self->header.glyph_bbox_wh_bits, byte_val, remaining_bits, &temp_value);
if (res != FR_OK) {
return res;
}
*bbox_h = temp_value;
return FR_OK;
}
static FRESULT read_bits(FIL *file, size_t num_bits, uint8_t *byte_val, uint8_t *remaining_bits, uint32_t *result) {
FRESULT res = FR_OK;
UINT bytes_read;
uint32_t value = 0;
// Bits will be lost when num_bits > 32. However, this is good for skipping bits.
size_t bits_needed = num_bits;
while (bits_needed > 0) {
// If no bits remaining, read a new byte
if (*remaining_bits == 0) {
res = f_read(file, byte_val, 1, &bytes_read);
if (res != FR_OK || bytes_read < 1) {
return FR_DISK_ERR;
}
*remaining_bits = 8;
}
// Calculate how many bits to take from current byte
uint8_t bits_to_take = (*remaining_bits < bits_needed) ? *remaining_bits : bits_needed;
value = (value << bits_to_take) | (*byte_val >> (8 - bits_to_take));
// Update state
*remaining_bits -= bits_to_take;
bits_needed -= bits_to_take;
// Shift byte for next read
*byte_val <<= bits_to_take;
*byte_val &= 0xFF;
}
if (result != NULL) {
*result = value;
}
return FR_OK;
}

View file

@ -0,0 +1,75 @@
// 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
#include "py/obj.h"
#include "shared-module/displayio/Bitmap.h"
#include "lib/oofatfs/ff.h"
#define LVFONTIO_INVALID_CODEPOINT 0xFFFFFFFF
// LV Font header information
typedef struct {
// Font size and metrics
uint16_t font_size;
uint16_t ascent;
uint16_t default_advance_width;
// Encoding formats
uint8_t index_to_loc_format;
uint8_t bits_per_pixel;
uint8_t glyph_bbox_xy_bits;
uint8_t glyph_bbox_wh_bits;
uint8_t glyph_advance_bits;
// Calculated values
uint8_t glyph_header_bits;
uint8_t glyph_header_bytes;
} lvfontio_header_t;
// Mapping of codepoint ranges to glyph IDs
typedef struct {
uint32_t range_start; // Start of codepoint range
uint32_t range_end; // End of codepoint range (exclusive)
uint16_t glyph_offset; // Offset to apply to codepoint
uint8_t format_type; // Format type: 0=sparse mapping, 2=range to range, 3=direct mapping
uint16_t entries_count; // Number of entries in sparse data
uint32_t data_offset; // File offset to the cmap data
} lvfontio_cmap_range_t;
typedef struct {
mp_obj_base_t base;
// Bitmap containing cached glyphs
displayio_bitmap_t *bitmap;
// Source of font file path (either a const char* or a copied string)
const char *file_path;
// Array mapping glyph indices to codepoints
uint32_t *codepoints;
// Array of reference counts for each glyph slot
uint16_t *reference_counts; // Use uint16_t to handle higher reference counts
// Maximum number of glyphs to cache at once
uint16_t max_glyphs;
// Flag indicating whether to use m_malloc (true) or port_malloc (false)
bool use_gc_allocator;
uint8_t half_width_px;
FIL file;
bool file_is_open;
// Font metrics information loaded from file
lvfontio_header_t header;
// CMAP information
lvfontio_cmap_range_t *cmap_ranges;
uint16_t cmap_range_count;
// Offsets for tables in the file
uint32_t loca_table_offset;
uint32_t glyf_table_offset;
uint32_t max_cid;
} lvfontio_ondiskfont_t;

View file

@ -0,0 +1,5 @@
// 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

View file

@ -10,20 +10,150 @@
#include "shared-bindings/displayio/TileGrid.h"
#include "shared-bindings/displayio/Palette.h"
#include "shared-bindings/terminalio/Terminal.h"
#include "shared-bindings/fontio/BuiltinFont.h"
#if CIRCUITPY_LVFONTIO
#include "shared-bindings/lvfontio/OnDiskFont.h"
#endif
#if CIRCUITPY_STATUS_BAR
#include "shared-bindings/supervisor/__init__.h"
#include "shared-bindings/supervisor/StatusBar.h"
#endif
void terminalio_terminal_clear_status_bar(terminalio_terminal_obj_t *self) {
if (self->status_bar) {
common_hal_displayio_tilegrid_set_all_tiles(self->status_bar, 0);
#include "supervisor/shared/serial.h"
uint16_t terminalio_terminal_get_glyph_index(mp_obj_t font, mp_uint_t codepoint, bool *is_full_width) {
if (is_full_width != NULL) {
*is_full_width = false; // Default to not full width
}
#if CIRCUITPY_LVFONTIO
if (mp_obj_is_type(font, &lvfontio_ondiskfont_type)) {
// For LV fonts, we need to cache the glyph first
lvfontio_ondiskfont_t *lv_font = MP_OBJ_TO_PTR(font);
bool full_width = false;
int16_t slot = common_hal_lvfontio_ondiskfont_cache_glyph(lv_font, codepoint, &full_width);
if (is_full_width != NULL) {
*is_full_width = full_width;
}
if (slot == -1) {
// Not found or couldn't cache
return 0xffff;
}
return (uint16_t)slot;
}
#endif
#if CIRCUITPY_FONTIO
if (mp_obj_is_type(font, &fontio_builtinfont_type)) {
// Use the standard fontio function
fontio_builtinfont_t *fontio_font = MP_OBJ_TO_PTR(font);
uint8_t index = fontio_builtinfont_get_glyph_index(fontio_font, codepoint);
if (index == 0xff) {
return 0xffff;
}
return index;
}
#endif
// Unsupported font type
return 0xffff;
}
static void wrap_cursor(uint16_t width, uint16_t height, uint16_t *cursor_x, uint16_t *cursor_y) {
if (*cursor_x >= width) {
*cursor_y = *cursor_y + 1;
*cursor_x %= width;
}
if (*cursor_y >= height) {
*cursor_y %= height;
}
}
static void release_current_glyph(displayio_tilegrid_t *tilegrid, mp_obj_t font, uint16_t x, uint16_t y) {
#if CIRCUITPY_LVFONTIO
if (!mp_obj_is_type(font, &lvfontio_ondiskfont_type)) {
return;
}
uint16_t current_tile = common_hal_displayio_tilegrid_get_tile(tilegrid, x, y);
if (current_tile == 0) {
}
common_hal_lvfontio_ondiskfont_release_glyph(MP_OBJ_TO_PTR(font), current_tile);
#endif
}
static void terminalio_terminal_set_tile(terminalio_terminal_obj_t *self, bool status_bar, mp_uint_t character, bool release_glyphs) {
displayio_tilegrid_t *tilegrid = self->scroll_area;
uint16_t *x = &self->cursor_x;
uint16_t *y = &self->cursor_y;
uint16_t w = self->scroll_area->width_in_tiles;
uint16_t h = self->scroll_area->height_in_tiles;
if (status_bar) {
tilegrid = self->status_bar;
x = &self->status_x;
y = &self->status_y;
w = self->status_bar->width_in_tiles;
h = self->status_bar->height_in_tiles;
}
if (release_glyphs) {
release_current_glyph(tilegrid, self->font, *x, *y);
}
bool is_full_width;
uint16_t new_tile = terminalio_terminal_get_glyph_index(self->font, character, &is_full_width);
if (new_tile == 0xffff) {
// Missing glyph.
return;
}
// If there is only half width left, then fill it with a space and wrap to the next line.
if (is_full_width && *x == w - 1) {
uint16_t space = terminalio_terminal_get_glyph_index(self->font, ' ', NULL);
common_hal_displayio_tilegrid_set_tile(tilegrid, *x, *y, space);
*x = *x + 1;
wrap_cursor(w, h, x, y);
if (release_glyphs) {
release_current_glyph(tilegrid, self->font, *x, *y);
}
}
common_hal_displayio_tilegrid_set_tile(tilegrid, *x, *y, new_tile);
*x = *x + 1;
wrap_cursor(w, h, x, y);
if (is_full_width) {
if (release_glyphs) {
release_current_glyph(tilegrid, self->font, *x, *y);
}
common_hal_displayio_tilegrid_set_tile(tilegrid, *x, *y, new_tile + 1);
*x = *x + 1;
wrap_cursor(w, h, x, y);
}
}
// Helper function to set all tiles in a tilegrid with optional glyph release
static void terminalio_terminal_set_all_tiles(terminalio_terminal_obj_t *self, bool status_bar, mp_uint_t character, bool release_glyphs) {
uint16_t *x = &self->cursor_x;
uint16_t *y = &self->cursor_y;
if (status_bar) {
x = &self->status_x;
y = &self->status_y;
}
*x = 0;
*y = 0;
terminalio_terminal_set_tile(self, status_bar, character, release_glyphs);
while (*x != 0 || *y != 0) {
terminalio_terminal_set_tile(self, status_bar, character, release_glyphs);
}
}
void terminalio_terminal_clear_status_bar(terminalio_terminal_obj_t *self) {
if (self->status_bar) {
terminalio_terminal_set_all_tiles(self, true, ' ', true);
}
}
void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self,
displayio_tilegrid_t *scroll_area, const fontio_builtinfont_t *font,
displayio_tilegrid_t *scroll_area, mp_obj_t font,
displayio_tilegrid_t *status_bar) {
self->cursor_x = 0;
self->cursor_y = 0;
@ -35,9 +165,9 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self,
self->first_row = 0;
self->vt_scroll_top = 0;
self->vt_scroll_end = self->scroll_area->height_in_tiles - 1;
common_hal_displayio_tilegrid_set_all_tiles(self->scroll_area, 0);
terminalio_terminal_set_all_tiles(self, false, ' ', false);
if (self->status_bar) {
common_hal_displayio_tilegrid_set_all_tiles(self->status_bar, 0);
terminalio_terminal_set_all_tiles(self, true, ' ', false);
}
common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, 1);
@ -85,29 +215,16 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
self->osc_command == 0 &&
self->status_bar != NULL &&
self->status_y < self->status_bar->height_in_tiles) {
uint8_t tile_index = fontio_builtinfont_get_glyph_index(self->font, c);
if (tile_index != 0xff) {
// Clear the tile grid before we start putting new info.
if (self->status_x == 0 && self->status_y == 0) {
common_hal_displayio_tilegrid_set_all_tiles(self->status_bar, 0);
}
common_hal_displayio_tilegrid_set_tile(self->status_bar, self->status_x, self->status_y, tile_index);
self->status_x++;
if (self->status_x >= self->status_bar->width_in_tiles) {
self->status_y++;
self->status_x %= self->status_bar->width_in_tiles;
}
// Clear the tile grid before we start putting new info.
if (self->status_x == 0 && self->status_y == 0) {
terminalio_terminal_set_all_tiles(self, true, ' ', true);
}
terminalio_terminal_set_tile(self, true, c, true);
}
continue;
}
// Always handle ASCII.
if (c < 128) {
if (c >= 0x20 && c <= 0x7e) {
uint8_t tile_index = fontio_builtinfont_get_glyph_index(self->font, c);
common_hal_displayio_tilegrid_set_tile(self->scroll_area, self->cursor_x, self->cursor_y, tile_index);
self->cursor_x++;
} else if (c == '\r') {
if (c < 0x20) {
if (c == '\r') {
self->cursor_x = 0;
} else if (c == '\n') {
self->cursor_y++;
@ -162,6 +279,8 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
#endif
} else {
if (c == 'K') {
int16_t original_cursor_x = self->cursor_x;
int16_t original_cursor_y = self->cursor_y;
int16_t clr_start = self->cursor_x;
int16_t clr_end = self->scroll_area->width_in_tiles;
#if CIRCUITPY_TERMINALIO_VT100
@ -171,11 +290,14 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
} else if (vt_args[0] == 2) {
clr_start = 0;
}
self->cursor_x = clr_start;
#endif
// Clear the (start/rest/all) of the line.
for (uint16_t k = clr_start; k < clr_end; k++) {
common_hal_displayio_tilegrid_set_tile(self->scroll_area, k, self->cursor_y, 0);
terminalio_terminal_set_tile(self, false, ' ', true);
}
self->cursor_x = original_cursor_x;
self->cursor_y = original_cursor_y;
} else if (c == 'D') {
if (vt_args[0] > self->cursor_x) {
self->cursor_x = 0;
@ -186,7 +308,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
if (vt_args[0] == 2) {
common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, 0);
self->cursor_x = self->cursor_y = start_y = 0;
common_hal_displayio_tilegrid_set_all_tiles(self->scroll_area, 0);
terminalio_terminal_set_all_tiles(self, false, ' ', true);
}
} else if (c == 'H') {
if (vt_args[0] > 0) {
@ -240,16 +362,20 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
self->cursor_y = self->scroll_area->height_in_tiles - 1;
}
} else {
if (self->vt_scroll_top != 0 || self->vt_scroll_end != self->scroll_area->height_in_tiles) {
if (self->vt_scroll_top != 0 || self->vt_scroll_end != self->scroll_area->height_in_tiles - 1) {
// Scroll range defined, manually move tiles to perform scroll
for (int16_t irow = self->vt_scroll_end - 1; irow >= self->vt_scroll_top; irow--) {
for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) {
common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, SCRNMOD(irow + 1), common_hal_displayio_tilegrid_get_tile(self->scroll_area, icol, SCRNMOD(irow)));
}
}
self->cursor_x = 0;
int16_t old_y = self->cursor_y;
// Fill the row with spaces.
for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) {
common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0);
terminalio_terminal_set_tile(self, false, ' ', true);
}
self->cursor_y = old_y;
} else {
// Full screen scroll, just set new top_y pointer and clear row
if (self->cursor_y > 0) {
@ -257,8 +383,12 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
} else {
common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, self->scroll_area->height_in_tiles - 1);
}
for (uint16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) {
common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->scroll_area->top_left_y, 0);
self->cursor_x = 0;
self->cursor_y = self->scroll_area->top_left_y;
// Fill the row with spaces.
for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) {
terminalio_terminal_set_tile(self, false, ' ', true);
}
self->cursor_y = self->scroll_area->top_left_y;
}
@ -277,12 +407,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
}
}
} else {
uint8_t tile_index = fontio_builtinfont_get_glyph_index(self->font, c);
if (tile_index != 0xff) {
common_hal_displayio_tilegrid_set_tile(self->scroll_area, self->cursor_x, self->cursor_y, tile_index);
self->cursor_x++;
}
terminalio_terminal_set_tile(self, false, c, true);
}
if (self->cursor_x >= self->scroll_area->width_in_tiles) {
self->cursor_y++;
@ -294,7 +419,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
if (self->cursor_y != start_y) {
if (((self->cursor_y + self->scroll_area->height_in_tiles) - 1) % self->scroll_area->height_in_tiles == SCRNMOD(self->vt_scroll_end)) {
#if CIRCUITPY_TERMINALIO_VT100
if (self->vt_scroll_top != 0 || self->vt_scroll_end != self->scroll_area->height_in_tiles) {
if (self->vt_scroll_top != 0 || self->vt_scroll_end != self->scroll_area->height_in_tiles - 1) {
// Scroll range defined, manually move tiles to perform scroll
self->cursor_y = SCRNMOD(self->vt_scroll_end);
@ -305,15 +430,18 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
}
}
#endif
if (self->vt_scroll_top == 0 && self->vt_scroll_end == self->scroll_area->height_in_tiles) {
if (self->vt_scroll_top == 0 && self->vt_scroll_end == self->scroll_area->height_in_tiles - 1) {
// Full screen scroll, just set new top_y pointer
common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, (self->cursor_y + self->scroll_area->height_in_tiles + 1) % self->scroll_area->height_in_tiles);
}
// clear the new row in case of scroll up
self->cursor_x = 0;
int16_t old_y = self->cursor_y;
for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) {
common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0);
terminalio_terminal_set_tile(self, false, ' ', true);
}
self->cursor_x = 0;
self->cursor_y = old_y;
}
start_y = self->cursor_y;
}

View file

@ -15,7 +15,7 @@
typedef struct {
mp_obj_base_t base;
const fontio_builtinfont_t *font;
mp_obj_t font; // Can be fontio_builtinfont_t or lvfontio_ondiskfont_t
uint16_t cursor_x;
uint16_t cursor_y;
displayio_tilegrid_t *scroll_area;
@ -30,3 +30,4 @@ typedef struct {
} terminalio_terminal_obj_t;
extern void terminalio_terminal_clear_status_bar(terminalio_terminal_obj_t *self);
uint16_t terminalio_terminal_get_glyph_index(mp_obj_t font, mp_uint_t codepoint, bool *is_full_width);

View file

@ -91,7 +91,7 @@ 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) {
mp_obj_t module_fun;
mp_obj_t module_fun = mp_const_none;
// CIRCUITPY-CHANGE
#if CIRCUITPY_ATEXIT
if (!(exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT))
@ -157,7 +157,7 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input
mp_call_function_n_kw(callback->func, callback->n_pos, callback->n_kw, callback->args);
} else
#endif
{
if (module_fun != mp_const_none) {
mp_call_function_0(module_fun);
}
mp_hal_set_interrupt_char(-1); // disable interrupt

View file

@ -7,8 +7,10 @@
#include "supervisor/shared/display.h"
#include <string.h>
#include "supervisor/port.h"
#include "py/mpstate.h"
#include "py/gc.h"
#include "shared-bindings/displayio/Bitmap.h"
#include "shared-bindings/displayio/Group.h"
#include "shared-bindings/displayio/Palette.h"
@ -39,6 +41,77 @@
#if CIRCUITPY_OS_GETENV
#include "shared-module/os/__init__.h"
#endif
#if CIRCUITPY_LVFONTIO
#include "shared-bindings/lvfontio/OnDiskFont.h"
#include "supervisor/filesystem.h"
#include "extmod/vfs_fat.h"
#include "lib/oofatfs/ff.h"
#include "supervisor/shared/serial.h"
// Check if a custom font file exists and return its path if found
// Returns true if font file exists, false otherwise
static bool check_for_custom_font(const char **font_path_out) {
if (!filesystem_present()) {
return false;
}
fs_user_mount_t *vfs = filesystem_circuitpy();
if (vfs == NULL) {
return false;
}
// Use FATFS directly to check if file exists
FILINFO file_info;
const char *default_font_path = "/fonts/terminal.lvfontbin";
const char *font_path = default_font_path;
#if CIRCUITPY_OS_GETENV
// 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) {
// Use custom font path from environment variable
font_path = custom_font_path;
}
#endif
FRESULT result = f_stat(&vfs->fatfs, font_path, &file_info);
if (result == FR_OK) {
if (font_path_out != NULL) {
*font_path_out = font_path;
}
return true;
}
// If custom font path doesn't exist, use default font
font_path = default_font_path;
result = f_stat(&vfs->fatfs, font_path, &file_info);
if (result == FR_OK) {
if (font_path_out != NULL) {
*font_path_out = font_path;
}
return true;
}
return false;
}
// Initialize a BuiltinFont object with the specified font file and max_slots
// Returns true on success, false on failure
static bool init_lvfont(lvfontio_ondiskfont_t *font, const char *font_path, uint16_t max_slots) {
if (font == NULL) {
return false;
}
font->base.type = &lvfontio_ondiskfont_type;
// Pass false for use_gc_allocator during startup when garbage collector isn't fully initialized
common_hal_lvfontio_ondiskfont_construct(font, font_path, max_slots, false);
return !common_hal_lvfontio_ondiskfont_deinited(font);
}
#endif
#endif
#if CIRCUITPY_REPL_LOGO
@ -52,29 +125,66 @@ static uint8_t *tilegrid_tiles = NULL;
static size_t tilegrid_tiles_size = 0;
#endif
#if CIRCUITPY_LVFONTIO
static lvfontio_ondiskfont_t *lvfont = NULL;
#endif
void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
if (supervisor_terminal_started()) {
return;
}
#if CIRCUITPY_TERMINALIO
// Default the scale to 2 because we may show blinka without the terminal for
// languages that don't have font support.
mp_int_t scale = 2;
#if CIRCUITPY_TERMINALIO
displayio_tilegrid_t *scroll_area = &supervisor_terminal_scroll_area_text_grid;
displayio_tilegrid_t *status_bar = &supervisor_terminal_status_bar_text_grid;
bool reset_tiles = false;
uint16_t width_in_tiles = width_px / scroll_area->tile_width;
uint16_t glyph_width = 0;
uint16_t glyph_height = 0;
#if CIRCUITPY_LVFONTIO
// Check if we have a custom terminal font in the filesystem
bool use_lv_font = false;
const char *font_path = NULL;
if (check_for_custom_font(&font_path)) {
// Initialize a temporary font just to get dimensions
lvfontio_ondiskfont_t temp_font;
if (init_lvfont(&temp_font, font_path, 1)) {
// Get the font dimensions
common_hal_lvfontio_ondiskfont_get_dimensions(&temp_font, &glyph_width, &glyph_height);
// Clean up the temp font - we'll create a proper one later
common_hal_lvfontio_ondiskfont_deinit(&temp_font);
use_lv_font = true;
reset_tiles = true;
// TODO: We may want to detect when the files modified time hasn't changed.
}
}
#endif
#if CIRCUITPY_FONTIO
if (glyph_width == 0) {
glyph_width = supervisor_terminal_font.width;
glyph_height = supervisor_terminal_font.height;
}
#endif
uint16_t width_in_tiles = width_px / glyph_width;
// determine scale based on width
if (width_in_tiles <= 80) {
if (width_in_tiles <= 120) {
scale = 1;
}
#if CIRCUITPY_OS_GETENV
(void)common_hal_os_getenv_int("CIRCUITPY_TERMINAL_SCALE", &scale);
#endif
width_in_tiles = MAX(1, width_px / (scroll_area->tile_width * scale));
uint16_t height_in_tiles = MAX(2, height_px / (scroll_area->tile_height * scale));
width_in_tiles = MAX(1, width_px / (glyph_width * scale));
uint16_t height_in_tiles = MAX(2, height_px / (glyph_height * scale));
uint16_t total_tiles = width_in_tiles * height_in_tiles;
@ -83,69 +193,121 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
(scroll_area->height_in_tiles != height_in_tiles - 1)) {
reset_tiles = true;
}
// Reuse the previous allocation if possible
if (tilegrid_tiles) {
if (tilegrid_tiles_size != total_tiles) {
port_free(tilegrid_tiles);
tilegrid_tiles = NULL;
tilegrid_tiles_size = 0;
reset_tiles = true;
}
}
if (!tilegrid_tiles) {
tilegrid_tiles = port_malloc(total_tiles, false);
reset_tiles = true;
if (!tilegrid_tiles) {
return;
}
circuitpython_splash.scale = scale;
if (!reset_tiles) {
return;
}
if (reset_tiles) {
// Adjust the display dimensions to account for scale of the outer group.
width_px /= scale;
height_px /= scale;
// Adjust the display dimensions to account for scale of the outer group.
width_px /= scale;
height_px /= scale;
// Number of tiles from the left edge to inset the status bar.
size_t min_left_padding = 0;
#if CIRCUITPY_REPL_LOGO
// Blinka + 1 px padding minimum
min_left_padding = supervisor_blinka_sprite.pixel_width + 1;
// Align the status bar to the bottom of the logo.
status_bar->y = supervisor_blinka_sprite.pixel_height - status_bar->tile_height;
#else
status_bar->y = 0;
#endif
status_bar->width_in_tiles = (width_px - min_left_padding) / status_bar->tile_width;
status_bar->height_in_tiles = 1;
status_bar->pixel_width = status_bar->width_in_tiles * status_bar->tile_width;
status_bar->pixel_height = status_bar->tile_height;
// Right align the status bar.
status_bar->x = width_px - status_bar->pixel_width;
status_bar->top_left_y = 0;
status_bar->tiles = tilegrid_tiles;
status_bar->full_change = true;
// Number of tiles from the left edge to inset the status bar.
size_t min_left_padding = 0;
status_bar->tile_width = glyph_width;
status_bar->tile_height = glyph_height;
#if CIRCUITPY_REPL_LOGO
// Blinka + 1 px padding minimum
min_left_padding = supervisor_blinka_sprite.pixel_width + 1;
// Align the status bar to the bottom of the logo.
status_bar->y = supervisor_blinka_sprite.pixel_height - status_bar->tile_height;
#else
status_bar->y = 0;
#endif
status_bar->width_in_tiles = (width_px - min_left_padding) / status_bar->tile_width;
status_bar->height_in_tiles = 1;
status_bar->pixel_width = status_bar->width_in_tiles * status_bar->tile_width;
status_bar->pixel_height = status_bar->tile_height;
// Right align the status bar.
status_bar->x = width_px - status_bar->pixel_width;
status_bar->top_left_y = 0;
status_bar->full_change = true;
scroll_area->width_in_tiles = width_in_tiles;
// Leave space for the status bar, no matter if we have logo or not.
scroll_area->height_in_tiles = height_in_tiles - 1;
scroll_area->pixel_width = scroll_area->width_in_tiles * scroll_area->tile_width;
scroll_area->pixel_height = scroll_area->height_in_tiles * scroll_area->tile_height;
// Right align the scroll area to give margin to the start of each line.
scroll_area->x = width_px - scroll_area->pixel_width;
scroll_area->top_left_y = 0;
// Align the scroll area to the bottom so that the newest line isn't cutoff. The top line
// may be clipped by the status bar and that's ok.
scroll_area->y = height_px - scroll_area->pixel_height;
scroll_area->tiles = tilegrid_tiles + width_in_tiles;
scroll_area->full_change = true;
scroll_area->tile_width = glyph_width;
scroll_area->tile_height = glyph_height;
scroll_area->width_in_tiles = width_in_tiles;
// Leave space for the status bar, no matter if we have logo or not.
scroll_area->height_in_tiles = height_in_tiles - 1;
scroll_area->pixel_width = scroll_area->width_in_tiles * scroll_area->tile_width;
scroll_area->pixel_height = scroll_area->height_in_tiles * scroll_area->tile_height;
// Right align the scroll area to give margin to the start of each line.
scroll_area->x = width_px - scroll_area->pixel_width;
scroll_area->top_left_y = 0;
// Align the scroll area to the bottom so that the newest line isn't cutoff. The top line
// may be clipped by the status bar and that's ok.
scroll_area->y = height_px - scroll_area->pixel_height;
scroll_area->full_change = true;
common_hal_terminalio_terminal_construct(&supervisor_terminal, scroll_area, &supervisor_terminal_font, status_bar);
mp_obj_t new_bitmap = mp_const_none;
mp_obj_t new_font = mp_const_none;
// Do not update status bar until after boot.py has run, in case it is disabled.
#if CIRCUITPY_LVFONTIO
if (lvfont != NULL) {
common_hal_lvfontio_ondiskfont_deinit(lvfont);
// This will also free internal buffers that may change size.
port_free(lvfont);
lvfont = NULL;
}
if (use_lv_font) {
// We found a custom terminal font file, use it instead of the built-in font
lvfont = port_malloc(sizeof(lvfontio_ondiskfont_t), false);
if (lvfont != NULL) {
// Use the number of tiles in the terminal and status bar for the number of slots
// This ensures we have enough slots to display all characters that could appear on screen
uint16_t num_slots = width_in_tiles * height_in_tiles;
// Initialize the font with our helper function
if (init_lvfont(lvfont, font_path, num_slots)) {
// Get the bitmap from the font
new_bitmap = common_hal_lvfontio_ondiskfont_get_bitmap(lvfont);
new_font = MP_OBJ_FROM_PTR(lvfont);
} else {
// If font initialization failed, free the memory and fall back to built-in font
port_free(lvfont);
lvfont = NULL;
use_lv_font = false;
}
}
}
#endif
#if CIRCUITPY_FONTIO
if (new_font == mp_const_none) {
new_bitmap = MP_OBJ_FROM_PTR(supervisor_terminal_font.bitmap);
new_font = MP_OBJ_FROM_PTR(&supervisor_terminal_font);
}
#endif
circuitpython_splash.scale = scale;
if (new_font != mp_const_none) {
size_t total_values = common_hal_displayio_bitmap_get_width(new_bitmap) / glyph_width;
if (tilegrid_tiles) {
port_free(tilegrid_tiles);
tilegrid_tiles = NULL;
}
size_t bytes_per_tile = 1;
if (total_tiles > 255) {
// Two bytes per tile.
bytes_per_tile = 2;
}
tilegrid_tiles = port_malloc(total_tiles * bytes_per_tile, false);
if (!tilegrid_tiles) {
return;
}
status_bar->tiles = tilegrid_tiles;
status_bar->tiles_in_bitmap = total_values;
status_bar->bitmap_width_in_tiles = total_values;
scroll_area->tiles = tilegrid_tiles + width_in_tiles * bytes_per_tile;
scroll_area->tiles_in_bitmap = total_values;
scroll_area->bitmap_width_in_tiles = total_values;
common_hal_displayio_tilegrid_set_bitmap(scroll_area, new_bitmap);
common_hal_displayio_tilegrid_set_bitmap(status_bar, new_bitmap);
common_hal_terminalio_terminal_construct(&supervisor_terminal, scroll_area,
new_font, status_bar);
}
#endif
}
void supervisor_stop_terminal(void) {

View file

@ -366,7 +366,7 @@ c_file.write(
"""\
terminalio_terminal_obj_t supervisor_terminal = {
.base = { .type = &terminalio_terminal_type },
.font = &supervisor_terminal_font,
.font = MP_OBJ_FROM_PTR(&supervisor_terminal_font),
.cursor_x = 0,
.cursor_y = 0,
.scroll_area = NULL,