Skip to content
This repository was archived by the owner on Oct 19, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 0 additions & 107 deletions .github/workflows/clean-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,110 +69,3 @@ jobs:
- name: Run tests/test_lifecycle_api.py under the built interpreter
run: |
./micropython/ports/unix/build-standard/micropython displayif/tests/test_lifecycle_api.py

- name: Run tests/jpegio/test_jpegio.py under the built interpreter
# The jpegio Phase 1 gate: the corpus in tests/jpegio/frames against
# the Pillow reference and TJpgDec's golden digests (no Pillow needed).
run: |
./micropython/ports/unix/build-standard/micropython displayif/tests/jpegio/test_jpegio.py

- name: Run tests/jpegio/test_jpegio_lvgl.py (must print SKIP -- no lvgl here)
# This leg is the only one that can check the decoder-less contract:
# register_lvgl_decoder() and lvgl_decoders() are module attributes on
# every build (they must be, or the CMake ports' QSTR pass never sees
# their names -- see src/jpegio/README.md), the first raising
# RuntimeError here, the second returning ().
run: |
./micropython/ports/unix/build-standard/micropython displayif/tests/jpegio/test_jpegio_lvgl.py | tee lvgl.out
grep -q 'register_lvgl_decoder() -> RuntimeError' lvgl.out
grep -q 'lvgl_decoders() == ()' lvgl.out
grep -q '^SKIP' lvgl.out

# Scenario: the same stranger adds the LVGL family. jpegio Phase 2 (org
# docs/jpegio-vision.md, "no LVGL fork"): LVGL's own TJPGD is off by config
# in lvgl-bindings' lv_conf.h, displayif's vendored TJpgDec is the firmware's
# only one, and src/jpegio/lvgl_decoder.c registers it as LVGL's JPEG
# decoder when the lvgl-micropython sibling is on the USER_C_MODULES scan
# path (D4: displayif self-detects; nothing is passed by hand).
unix-lvgl-jpegio:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v7
with:
path: displayif

- name: Check out upstream MicroPython v1.28.0
uses: actions/checkout@v7
with:
repository: micropython/micropython
ref: v1.29.0
path: micropython

# Pinned to the lvgl-bindings commit that turns LV_USE_TJPGD off on
# MicroPython/CircuitPython (tjpgd_init/deinit CPython-only) and the
# lvgl-micropython sync that consumes it. Move both together: the
# lvgl-micropython build refuses a bindings checkout that does not
# match its LVGL_BINDINGS_COMMIT pin.
- name: Check out lvgl-bindings (LV_USE_TJPGD 0 on MicroPython)
uses: actions/checkout@v7
with:
repository: PyDevices/lvgl-bindings
ref: d5f3d341e6bcfc97d52d66f776587c215c95ff4d
path: lvgl-bindings
submodules: true

- name: Check out lvgl-micropython (pins that lvgl-bindings commit)
uses: actions/checkout@v7
with:
repository: PyDevices/lvgl-micropython
ref: 410e2e8dcf38e316f5da7bc63b35ba4b3fd07dfd
path: lvgl-micropython

- name: Install SDL2
run: |
sudo apt-get update
sudo apt-get install -y libsdl2-dev

- name: Build the unix port with displayif + lvgl-micropython + lvgl-bindings
# Both modules are named by their own manifests (MicroPython 1.29
# c_module()), so a two-line manifest selects them and there is no
# USER_C_MODULES: passing the parent directory as well would include
# each module twice. FROZEN_MANIFEST also freezes lvgl-micropython's
# display_driver.py / fs_driver.py (the file-source test uses the
# latter). jpegio sees lvgl-micropython in USER_C_MODULES (appended by
# the manifest) and compiles its LVGL decoder.
run: |
printf 'include("displayif/manifest.py")\ninclude("lvgl-micropython/manifest.py")\n' > ci-manifest.py
make -C micropython/mpy-cross -j2
make -C micropython/ports/unix submodules
make -C micropython/ports/unix -j2 \
FROZEN_MANIFEST=$GITHUB_WORKSPACE/ci-manifest.py

- name: One TJpgDec in the firmware, and it is jpegio's
# Exactly one object defines jd_prepare (displayif's tjpgd.o; LVGL's
# tjpgd.o is empty under LV_USE_TJPGD 0), no jpegio_jd_ prefix left,
# and both jpegio.o and lvgl_decoder.o import it.
run: |
cd micropython/ports/unix/build-standard
find . -name '*.o' -exec nm -A {} + 2>/dev/null | grep -E ' T jd_(prepare|decomp)$' | tee jd.txt
test "$(grep -c ' T jd_prepare$' jd.txt)" = 1
grep -q '^./displayif/src/jpegio/tjpgd/tjpgd.o:.* T jd_prepare$' jd.txt
! find . -name '*.o' -exec nm -A {} + 2>/dev/null | grep -q 'jpegio_jd_'
nm displayif/src/jpegio/jpegio.o | grep -q ' U jd_prepare$'
nm displayif/src/jpegio/lvgl_decoder.o | grep -q ' U jd_decomp$'
test "$(find . -name tjpgd.o | wc -l)" = 2

- name: Run tests/jpegio/test_jpegio.py (goldens unchanged beside LVGL)
run: |
./micropython/ports/unix/build-standard/micropython displayif/tests/jpegio/test_jpegio.py

- name: Run tests/jpegio/test_jpegio_lvgl.py (the LVGL half of the Phase 2 gate)
run: |
./micropython/ports/unix/build-standard/micropython displayif/tests/jpegio/test_jpegio_lvgl.py | tee lvgl.out
! grep -q '^SKIP' lvgl.out
grep -q 'digests exact through lv.image: 3 of 3' lvgl.out

- name: Run lvgl-bindings' smoke test (tjpgd_init absent on MicroPython)
run: |
./micropython/ports/unix/build-standard/micropython lvgl-bindings/tools/test_lvgl_smoke.py
5 changes: 2 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

Native MicroPython display **interface** modules for PyDevices `displaydev` (`USER_C_MODULES`).
Portable code in `src/ports/common/`; SoC code under `src/ports/<mp-port>/`;
desktop SDL (`usdl2`) under `src/ports/desktop/usdl2/`; the `jpegio` JPEG
decoder (every port) under `src/jpegio/`. CircuitPython: MCU
desktop SDL (`usdl2`) under `src/ports/desktop/usdl2/`. The `jpegio` JPEG
decoder moved to micropython-pydevices' `modules/jpegio` (2026-10-06). CircuitPython: MCU
interfaces stay on stock CP; only `usdl2` uses `./apply_cp_patches.sh` (unix).

**Before editing lifecycle / soft-reset / a new board bring-up**, read:
Expand All @@ -21,7 +21,6 @@ attr / soft-reset patterns when changing siblings.
|------|----------|
| `src/include/` | Public headers (`displayif/` subdir) |
| `src/ports/` | Port C sources + per-port `micropython.mk` / `.cmake` (`common/`, `esp32/`, `desktop/usdl2/`, …) |
| `src/jpegio/` | `jpegio` JPEG decoder (CircuitPython API, vendored TJpgDec in `tjpgd/`); platform-neutral, built on every port; `lvgl_decoder.c` registers it as LVGL's JPEG decoder when the `lvgl-micropython` sibling usermod is in the build — [src/jpegio/README.md](src/jpegio/README.md) |
| `src/circuitpython_spike/` | CP unix spike for `usdl2` (copied by `apply_cp_patches.sh`) |
| `docs/` | Markdown docs (root keeps `README.md` and `AGENTS.md` only) |
| `docs/ports/` | Per-port notes moved from former `ports/*/README.md` |
Expand Down
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ failure modes (P4 `mipidsi`, Qualia `dotclockframebuffer.DotClockFramebuffer`):
| `picodvi` | `rp2` (RP2040 PIO / RP2350 HSTX) | **FBDisplay** |
| `rgbmatrix` | `esp32` (S3) / `mimxrt` (1062) / `samd` (SAMD51) / `rp2` | **FBDisplay** |
| `usdl2` | `desktop` (MicroPython `unix` / `windows`; CircuitPython unix via `apply_cp_patches.sh`) | **SDLDisplay** |
| `jpegio` | every port (`src/jpegio/`, platform-neutral; CircuitPython has it natively) | any — decodes JPEG to RGB565 for `blit_rect`; beside `lvgl-micropython` it is also LVGL's JPEG decoder ([docs](src/jpegio/README.md)) |
| stubs | `samd` / `rp2` / non-1062 mimxrt (`dotclockframebuffer.DotClockFramebuffer`, `mipidsi`); non-1176 mimxrt (`mipidsi`); non-S3 `qspibus` | ctor raises |


Expand Down Expand Up @@ -68,7 +67,7 @@ cd micropython/ports/unix && make submodules && make

The manifest freezes no Python; it only names the C module, and the build glue
picks the modules your port supports (see [docs/port-matrix.md](docs/port-matrix.md)).
On unix that is `usdl2` and `jpegio`; the bus and framebuffer modules are
On unix that is `usdl2`; the bus and framebuffer modules are
MCU-only. Tested on the unix port against MicroPython v1.29.0.

If you would rather not edit the MicroPython tree, write a manifest of your own
Expand Down Expand Up @@ -138,9 +137,8 @@ Then run the lifecycle API test under the same interpreter:
[the protomatter/ README](src/ports/common/rgbmatrix/protomatter/README.md)
for the identified upstream revision and license text.

`src/jpegio/tjpgd/` vendors ChaN's TJpgDec R0.03 (with patch1, via
CircuitPython's `lib/tjpgd`) under its own permissive notice; see
[src/jpegio/README.md](src/jpegio/README.md#notice--tjpgdec).
The JPEG decoder, `jpegio`, moved to micropython-pydevices'
[modules/jpegio](https://github.com/PyDevices/micropython-pydevices/tree/main/modules/jpegio) on 2026-10-06, with its vendored TJpgDec and its notice.

## Related

Expand Down
1 change: 0 additions & 1 deletion docs/newcomers.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ commands and shows how to combine several CMake user modules.
| `src/ports/common/` | Shared buses, helpers, RGB matrix code, and lifecycle support. |
| `src/ports/<port>/` | SoC-specific backends for ESP32, RP2, SAMD, and MIMXRT; `stm32` builds the portable buses only. |
| `src/ports/desktop/usdl2/` | SDL2 desktop backend for MicroPython unix and Windows. |
| `src/jpegio/` | Platform-neutral JPEG decoder and optional LVGL decoder integration. |
| `src/include/displayif/` | Public native headers. |
| `micropython.mk`, `micropython.cmake` | Make/CMake user-module entrypoints. |
| `docs/port-matrix.md` | Module/port/board-config support matrix. |
Expand Down
10 changes: 5 additions & 5 deletions docs/qstrs-and-usermod-defines.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ months looking like nothing.
A guarded name is only safe if something else collects it:

1. **It is in MicroPython's static pool** (`py/qstrdefs.h`) — `__init__`,
`__name__` and the rest. `src/jpegio/jpegio.c` relies on this for
`MP_QSTR___init__`, which is why the checker carries a short `CORE_POOL`
list. Add to that list only with the reason written down; the pool is
`__name__` and the rest. jpegio relied on this for `MP_QSTR___init__`
while it lived here (it's now micropython-pydevices' `modules/jpegio`), which
is why the checker has a `CORE_POOL` list, empty today. Add to that list only with the reason written down; the pool is
MicroPython's, and it changes between versions.
2. **The same file references it unguarded elsewhere.**
`src/ports/common/spi/mod_spibus.c` guards `sck`/`mosi`/`miso` behind
Expand All @@ -81,8 +81,8 @@ pass does, with no INTERFACE define:
| before | 0 | 14 |
| after | 14 | 14 |

`src/jpegio/README.md` has the same story from the day it was found, with the
LVGL decoder's specifics.
jpegio's README (now micropython-pydevices' `modules/jpegio/README.md`) has the
same story from the day it was found, with the LVGL decoder's specifics.

<!-- sources: displayif#24; the jpegio fix fb4fd6a; micropython v1.29.0
py/mkrules.cmake and py/py.mk -->
6 changes: 2 additions & 4 deletions micropython.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
# want displayif plus other modules — no aggregator file required, e.g.:
# -DUSER_C_MODULES="/path/to/displayif;/path/to/other_mod"
# Hardware interfaces build only on MCU ports. Desktop usdl2 is Make-only
# (unix/windows via micropython.mk); no cmake desktop path yet. `jpegio`
# builds everywhere.
# (unix/windows via micropython.mk); no cmake desktop path yet.

set(DISPLAYIF_MOD_DIR ${CMAKE_CURRENT_LIST_DIR})

Expand Down Expand Up @@ -76,5 +75,4 @@ if(DISPLAYIF_PORT_STM32)
include(${DISPLAYIF_MOD_DIR}/src/ports/stm32/micropython.cmake)
endif()

# JPEG decoder (`import jpegio`): platform-neutral C, built on every port.
include(${DISPLAYIF_MOD_DIR}/src/jpegio/micropython.cmake)
# The JPEG decoder, jpegio, moved to micropython-pydevices' modules/jpegio.
7 changes: 3 additions & 4 deletions micropython.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Discovered via USER_C_MODULES pointing at the workspace directory that
# contains this repo (its parent), e.g. `make USER_C_MODULES=../../..`.
# Hardware interfaces (spibus, dotclockframebuffer, …) build only on MCU ports.
# Desktop SDL (`usdl2`) builds on unix and windows ports. `jpegio` builds everywhere.
# Desktop SDL (`usdl2`) builds on unix and windows ports.

DISPLAYIF_MOD_DIR := $(USERMOD_DIR)

Expand Down Expand Up @@ -122,12 +122,11 @@ ifneq ($(DISPLAYIF_PORT_UNIX)$(DISPLAYIF_PORT_WINDOWS),00)
include $(DISPLAYIF_MOD_DIR)/src/ports/desktop/usdl2/micropython.mk
endif

# JPEG decoder (`import jpegio`): platform-neutral C, built on every port.
include $(DISPLAYIF_MOD_DIR)/src/jpegio/micropython.mk
# The JPEG decoder, jpegio, moved to micropython-pydevices' modules/jpegio.

# displayif_revision_obj, read as <module>.__revision__ on every module here.
# src/include is on the path here, not only in ports/common/micropython.mk,
# because a port that builds jpegio alone (webassembly) never includes that.
# because a port that builds no display module (webassembly) never includes that.
CFLAGS_USERMOD += -I$(DISPLAYIF_MOD_DIR)/src/include
SRC_USERMOD_C += $(DISPLAYIF_MOD_DIR)/src/ports/common/build.c

Expand Down
Loading
Loading