Conversation
libAtomVM/utils.h already provides UNUSED. Signed-off-by: Davide Bettio <davide@uninstall.it>
globalcontext_atomstring_from_term() was removed in libAtomVM 0.7. Signed-off-by: Davide Bettio <davide@uninstall.it>
font.c was previously included verbatim by every driver via array in the ESP32 build (and one more in the SDL build). Refactor into a proper compiled module so the data is linked once. font.c is renamed to font_data.c with the static qualifier removed on the array. A new font_data.h declares the array as extern and exposes FONTDATAMAX. All previous consumers (6 ESP32 drivers + the SDL display.c) now include font_data.h instead of font.c, and both CMakeLists.txt entries are updated to compile font_data.c. Signed-off-by: Davide Bettio <davide@uninstall.it>
display_items.h was previously included by every driver via init_item() and destroy_items() function bodies in the ESP32 build (and one more in the SDL build). Refactor into a proper compiled module so the bodies are linked once. Signed-off-by: Davide Bettio <davide@uninstall.it>
Extract the send_message helper (identical across 6 ESP32 drivers and message_helpers.h) into a shared display_message module. Also remove PendingReply, a vestigial struct defined in 6 files but never instantiated or referenced. Signed-off-by: Davide Bettio <davide@uninstall.it>
Extract the FreeRTOS queue, consume_mailbox callback, and process_messages task into a shared display_task module. All seven ESP32 drivers now embed struct DisplayTaskArgs and use the shared dispatch infrastructure via CONTAINER_OF. The consume_mailbox implementation adopts the ili948x variant (non-blocking enqueue with drop-oldest-on-overflow and proper disposal of dropped messages). Also removes unused display_enqueue_message from ili934x and stale mailbox.h include from display_driver.h. Signed-off-by: Davide Bettio <davide@uninstall.it>
Signed-off-by: Davide Bettio <davide@uninstall.it>
Extract writedata, writecommand, and writecmddata from the DCS LCD drivers into a shared module using struct SPIDCBus. Migrate st7789, ili934x, and ili948x to embed the bus sub-struct. Signed-off-by: Davide Bettio <davide@uninstall.it>
Extract alpha_blend_rgb565, rgba8888_color_to_rgb565, and related color helpers into a shared inline-header module. Drop the unused struct Screen parameter. Migrate st7789, ili934x, and ili948x. Signed-off-by: Davide Bettio <davide@uninstall.it>
Unify the per-driver struct Screen into a shared DCSLCDScreen that is the superset of all three: st7789's x_offset/y_offset, ili948x's bytes/bytes_out for RGB888, and the common w/h and pixel buffers. Migrate st7789, ili934x, and ili948x. Signed-off-by: Davide Bettio <davide@uninstall.it>
Extract set_paint_area (with offset support from st7789) and draw_buffer (with RGB888 path from ili948x) into a shared module. Consolidate generic MIPI DCS command macros under a DCS_LCD_ prefix. Zero-init DCSLCDScreen allocation for safe access to uninitialized offset fields. Migrate st7789, ili934x, and ili948x. Signed-off-by: Davide Bettio <davide@uninstall.it>
Extract the per-pixel scanline renderer (draw_x dispatcher and five draw_*_x helpers) into a shared module. All functions take const struct DCSLCDScreen *screen as their first parameter. Migrate st7789, ili934x, and ili948x. Signed-off-by: Davide Bettio <davide@uninstall.it>
Add driver for the Good Display GDEP073E01 7.3-inch ACeP panel (800x480, 7-color e-ink). Signed-off-by: Davide Bettio <davide@uninstall.it>
Add epaper_screen (shared type), epaper_color (palette- parameterized ACeP 7-color dithering), and epaper_draw (per-pixel draw pipeline). Extend spi_dc_driver with spi_dc_writedatan for variable-width writes. Migrate 5in65_acep_7c and gdep073e01 drivers. Signed-off-by: Davide Bettio <davide@uninstall.it>
Extract the monochrome draw_x dispatcher, five draw_*_x helpers, and Bayer 4x4 dithering into a shared module with struct MonoScreen. Migrate memory_display and ssd1306 drivers. Signed-off-by: Davide Bettio <davide@uninstall.it>
The pixels pointer update at the bottom of the inner loop used j / x_scale, but j is the current iteration's index. After the for-loop increments j, pixels still pointed at the old source column. Use (j + 1) / x_scale so the pointer is correct for the next iteration. Fixes a leftmost-column artifact visible on 4x-scaled images. Signed-off-by: Davide Bettio <davide@uninstall.it>
Both e-paper drivers allocated a DMA scanline buffer with heap_caps_malloc but never freed it. Add the missing free(buf) after spi_device_release_bus in each function. Signed-off-by: Davide Bettio <davide@uninstall.it>
Replace the placeholder pure-primary RGB values with real-world measurements taken from the physical panel. The calibrated values produce more accurate nearest-color matching during dithering. Signed-off-by: Davide Bettio <davide@uninstall.it>
Both headers have zero includers after the monochrome draw functions were extracted into mono_draw. The shared per-pixel draw pipeline and Bayer dither now live in mono_draw.c/h. Signed-off-by: Davide Bettio <davide@uninstall.it>
Move ufontlib from sdl_display/ to the component root. Fix the inverted magic check in ufont_parse and accept standard IFF container layout (FORM + size + uFL0 form type). Wire up register_font as a pre-dispatch handler in the shared display task, ufont_manager initialization, and the epd_draw_pixel rendering callback. Honor FgColor for anti-aliased text. Signed-off-by: Davide Bettio <davide@uninstall.it>
Apply lower_snake_case to SPI and SPI+DC helpers, add module prefixes to display_items, display_task, and display_message public functions, fix word boundaries in controller-specific init function names, convert enum values to PascalCase, and make file-local helpers static. Signed-off-by: Davide Bettio <davide@uninstall.it>
Add a Style Exception comment explaining that FONTDATAMAX and fontdata keep their original Linux kernel names (from lib/fonts/font_8x16.c) to simplify comparison with upstream. Per C_CODING_STYLE.md "Style Exception Documentation" section. No code changes. Signed-off-by: Davide Bettio <davide@uninstall.it>
Convert data_len in spi_display_dma_write/spi_display_write and items_len in display_items_delete/find_max_line_len/draw_x from int to size_t. Rename spi_data parameter to spi_disp. Signed-off-by: Davide Bettio <davide@uninstall.it>
The SDL build compiled ufontlib.c but never defined ENABLE_UFONT, so the rendering path in display_items.c was compiled out. The SDL driver also carried an outdated duplicate of struct Surface and epd_draw_pixel that was missing the fg_color field and hardcoding black. Remove the ESP_PLATFORM guard from the shared epd_draw_pixel in display_items.c, remove the stale SDL-local copy, and add -DENABLE_UFONT to the SDL CMake build. Signed-off-by: Davide Bettio <davide@uninstall.it>
The ufont rendering path hardcoded brcolor to 0 (transparent) when storing the pre-rendered glyph surface as a PrimitiveImage. This caused the scanline draw_image_x to early-return on the first transparent pixel, making the text invisible unless every pixel in the glyph bounding box had non-zero alpha. Use the background color from the display list tuple instead. Signed-off-by: Davide Bettio <davide@uninstall.it>
struct SPI was the shared state struct across all drivers. After the family split, the generic name no longer described the shape of any given driver. The SSD1306 family also drove it further out of truth: the driver uses I2C, not SPI. Rename to family-specific types: - DCS LCD drivers (ili934x, ili948x, st7789) -> DCSLCDDriver - E-paper drivers (5in65_acep_7c, gdep073e01) -> EpaperDriver - SSD1306 family -> OLEDDriver - memory_lcd -> MemoryLCDDriver Rename the matching FROM_CTX macros and the local `spi` variable to `driver`. Signed-off-by: Davide Bettio <davide@uninstall.it>
The built-in font width constant was duplicated in four draw modules. Move it next to FONTDATAMAX in font_data.h where it belongs with the font geometry. Signed-off-by: Davide Bettio <davide@uninstall.it>
The ufont text rendering path allocates a surface buffer proportional to the bounding box. On ESP32 this can exceed available heap for large text, and the missing NULL check crashes in memset. Signed-off-by: Davide Bettio <davide@uninstall.it>
Define a compact byte-array format for controller init sequences and an interpreter (dcs_lcd_execute_init_seq) that walks the table sending commands via spi_dc_write_cmd_data. Transcribe all 6 existing display_init_*() functions into const byte arrays with _Static_assert on each array size to catch any miscount at compile time. Arrays: ILI9341, ILI9342C, ILI9486, ILI9488, ST7789 std, ST7789 alt gamma 2. No caller changes yet — the old static init functions are still in use. Signed-off-by: Davide Bettio <davide@uninstall.it>
Replace display_init_9341(), display_init_9342c(), display_init_9486(), display_init_9488(), display_init_std(), and display_init_alt_gamma_2() with calls to dcs_lcd_execute_init_seq() reading the byte-array tables from dcs_lcd_commands.c. Remove the six static init functions and their now-unused controller register defines (keep TFTWIDTH/TFTHEIGHT). The display_init_using_list() Erlang-driven init path is unchanged. The delay() helper stays -- still used in the reset path and by display_init_using_list(). Bytes-on-the-wire are unchanged for every controller. Signed-off-by: Davide Bettio <davide@uninstall.it>
Define struct DCSLCDDesc and populate descriptors for the 6 compatible strings served by the DCS LCD drivers: ILI9341, ILI9342C, ILI9486, ILI9488, ST7789, ST7796. Each descriptor captures native resolution, SPI clock, pixel format, per-rotation MADCTL values, default color order, and the built-in init sequence pointer. Rotations not validated on the existing hardware are marked 0xFF. Signed-off-by: Davide Bettio <davide@uninstall.it>
Expose the SPI clock rate as an Erlang opt so applications can override the descriptor default. Signed-off-by: Davide Bettio <davide@uninstall.it>
Move the SWRESET, SLPOUT and DISPON commands (with their delays) into the per-controller init sequence tables. Each driver previously issued these manually around dcs_lcd_execute_init_seq; folding them into the tables lets a single shared driver execute the entire bring-up sequence with no controller-specific C code. ILI controllers gain a DISPON+120ms tail (matching st7789). ST7789 without a reset GPIO drops the explicit SWRESET+100ms in favour of SWRESET+5ms+SLPOUT+120ms -- both datasheet-compliant. Signed-off-by: Davide Bettio <davide@uninstall.it>
Move DCSLCDScreen from a file-static pointer into the DCSLCDDriver struct across all three DCS LCD drivers (ili934x, ili948x, st7789). Removes one global, one heap allocation, and one pointer indirection per driver. Calloc replaces malloc so the embedded screen's unused fields (offsets, bytes for non-9488) are zero-initialised. Also drop the explicit SWRESET, SLPOUT and DISPON commands each driver issued manually; they are now part of the controller's init sequence table. For st7789 this also drops the no-reset-GPIO SWRESET branch. Signed-off-by: Davide Bettio <davide@uninstall.it>
git mv st7789_display_driver.c -> dcs_lcd_display_driver.c; rename the create_port entry point and the log TAG accordingly. Pure rename -- sitronix,st7789 and sitronix,st7796 dispatch through the new function; ILI compatibles still route through their legacy drivers. Signed-off-by: Davide Bettio <davide@uninstall.it>
Generalise the driver into a single descriptor-driven implementation that can run any of the six DCS LCD controllers covered by the DCSLCDDesc table. A compatible-string lookup picks the descriptor; init sequence, MADCTL bytes, default geometry, default colour order, SPI clock and pixel size come from it. Hardware-touching code becomes uniform across controllers: MADCTL slots feed set_rotation (with 0xFF rejecting an unsupported rotation), pixel_bytes selects between RGB565 and RGB888 scanline paths, and the boot flow always emits an explicit INVON/INVOFF. init_list, init_seq_type, width/height, x_offset/y_offset, and color_order now apply to every controller (silently fixing the hardcoded-geometry FIXME the ILI934x driver carried). Signed-off-by: Davide Bettio <davide@uninstall.it>
Route the four ILI compatibles through the unified dcs_lcd_display_create_port and drop the now-orphaned ili934x and ili948x driver files. All six DCS LCD compatibles (ilitek,ili9341/ili9342c/ili9486/ili9488 and sitronix,st7789/st7796) are served by a single descriptor-driven driver, with x_offset/y_offset, color_order, init_list, width/height and an optional reset GPIO available uniformly. Signed-off-by: Davide Bettio <davide@uninstall.it>
The two e-paper drivers currently open-code their init sequences as long chains of spi_dc_write_command/data calls, with BUSY-polling (gdep073e01) or an embedded delay (acep 5.65") interleaved between commands. Each additional panel would add another ~30-60 lines in the same shape. Extract the sequences to declarative byte arrays in the format [CMD][FLAGS_LEN][DATA...][optional DELAY_MS], paired with a size_t length constant. The interpreter takes an extra wait_busy_between_cmds bool to cover the gdep073e01 convention without bloating the per-row format. _Static_assert on array sizes catches miscounted data bytes at build time. Signed-off-by: Davide Bettio <davide@uninstall.it>
Replace the per-panel chains of spi_dc_write_command/write_data calls (acep: 35 lines with an inline vTaskDelay; gdep073e01: 14 steps each followed by wait_busy_level) with a single call to epaper_execute_init_seq for each panel. The byte-array tables come from epaper_commands.c. For gdep073e01 the executor polls BUSY between commands via wait_busy_between_cmds=true. For acep the 100 ms delay between VDCS (0x82) and the second CDI (0x50) is encoded in the table via the delay flag. Bytes-on-the-wire are unchanged. Drop the now-unused gdep073e01 command-byte defines (PSR, PWRR, POF, POFS, PON, BTST1/2/3, DTM, DRF, PLL, CDI, TCON, TRES, REV, VDCS, T_VDCS, PWS, DSLP); the frame-protocol sites use raw hex to match the acep driver. Signed-off-by: Davide Bettio <davide@uninstall.it>
Introduce struct EPaperDesc with everything a unified driver needs to dispatch on compatible string: panel name, native dimensions, SPI clock, palette pointer + size, init sequence, optional per-frame preamble, and the post-frame refresh flags (DRF data byte, POF busy-wait level, periodic white-out interval). Instantiate two descriptors -- epaper_desc_acep7c and epaper_desc_gdep073e01 -- populated from the constants currently baked into the two driver files. The ACeP descriptor also ships a frame_preamble_seq encoding the 0x61 resolution command that today is open-coded in the driver's do_update and clear_screen paths. Signed-off-by: Davide Bettio <davide@uninstall.it>
Fold EpaperScreen into struct EpaperDriver as an embedded member and drop the file-static pointer across both e-paper drivers (acep, gdep073e01). The driver allocation via malloc() already reserves space for it, removing the separate calloc() and its attendant leak-on-driver-free. A prerequisite for the unified e-paper driver: multi-instance support needs every per-screen value to live behind the driver pointer recovered by EPAPER_DRIVER_FROM_CTX, not behind a file-static reachable from a single translation unit. Signed-off-by: Davide Bettio <davide@uninstall.it>
git mv gdep073e01_display_driver.c -> epaper_display_driver.c; rename the create_port entry point and the log TAG accordingly. Pure rename -- the gdep compatible dispatches through the new function, and the waveshare,5in65-acep-7c compatible still calls the separate acep driver file. Signed-off-by: Davide Bettio <davide@uninstall.it>
Generalise epaper_display_driver.c to drive both compatibles from
the per-panel EPaperDesc descriptors. A compatible-string lookup
picks the descriptor; dimensions, SPI clock, palette, init
sequence, per-frame preamble, periodic-refresh interval, and
post-frame refresh flags all come from it.
The driver also accepts an init_list Erlang-side override in the
tuple format used by the DCS LCD driver, extended with
{wait_busy_level, 0|1} for the BUSY-pin polling that e-paper
controllers typically require mid-init.
Route good-display/gdep073e01 and waveshare,5in65-acep-7c through
the single epaper_display_create_port dispatch entry.
Signed-off-by: Davide Bettio <davide@uninstall.it>
The waveshare,5in65-acep-7c compatible now dispatches through the unified epaper_display_driver.c, leaving the legacy 5in65_acep_7c_display_driver.c orphaned. Drop it and its CMakeLists.txt entry. Signed-off-by: Davide Bettio <davide@uninstall.it>
Introduce oled_commands.h/.c with a length-framed init-sequence executor and two init arrays (SSD1306/SH1106 minimal, SSD1315 full). The format ([CMD][FLAGS_LEN][DATA...][DELAY_MS]) matches epaper_commands.h verbatim so the codebase converges on one init-sequence convention. Unlike an inline init transaction, the executor owns the I2C transaction boundary -- one i2c_cmd_link per step -- so that any future vTaskDelay between steps actually waits between commands rather than being a no-op inside a queued cmd_link. Current SSD13xx init steps don't use the DELAY flag. Each array carries a _Static_assert on sizeof to catch miscounted data bytes at compile time. Signed-off-by: Davide Bettio <davide@uninstall.it>
Replace the inline i2c_master_write_byte loop and its long SSD1315/SSD1306 if/else fork with a single oled_execute_init_seq() call dispatched on driver->type. Bytes-on-the-wire are unchanged; the executor opens one i2c_cmd_handle_t per init step instead of batching the entire sequence into one transaction, which on the panel side just means extra stop/start conditions between commands. The optional invert command and the unconditional display ON now ride in a small post-executor transaction inside display_init. They depend on a runtime opt and are not panel-specific data, so they belong with the driver, not the per-variant init array. Drop CMD_SET_CHARGE_PUMP, CMD_SET_SEGMENT_REMAP, and CMD_SET_COM_SCAN_MODE: they were only referenced by the inline init that is being removed here. Signed-off-by: Davide Bettio <davide@uninstall.it>
Define struct OLEDDesc in oled_commands.h with the per-controller fields needed to drive SSD1306, SSD1315, and SH1106 from a single unified driver: dimensions, I2C address, init sequence pointer + length, and the two runtime-behavior flags that today require if/else branching on a display_type_t enum (column reset before each page write; data-stream prefix padding for SH1106's 132-pixel controller exposing a 128-pixel viewport). Instantiate the three descriptors. SSD1306 and SH1106 share the same minimal init array (charge-pump enable + segment / COM-scan remap); SSD1315 uses its own full init. Signed-off-by: Davide Bettio <davide@uninstall.it>
Fold MonoScreen into struct MemoryLCDDriver as an embedded member and drop the file-static pointer + its separate calloc. The per-screen state now travels with the driver pointer recovered by MEMORY_LCD_DRIVER_FROM_CTX, preparing multi-instance support for this driver. While here, accept width/height Erlang opts (defaults 400x240 for the LS027B4DH01) and resolve the `// FIXME: hardcoded width and height`. The new opt surface mirrors what DCS LCD already accepts. struct Screen and its DMA buffers stay at file scope here; they are specific to the Sharp frame format. vcom likewise stays a file-global. Signed-off-by: Davide Bettio <davide@uninstall.it>
Move the Sharp frame-format DMA buffers (pixels, dma_out) and the VCOM toggle state from file scope into struct MemoryLCDDriver as embedded members. Drop the struct Screen wrapper entirely; w/h are carried by the embedded MonoScreen and pixels/dma_out live directly on the driver. Rewrite get_vcom() as next_vcom(driver), advancing the toggle bit on the driver pointer recovered by MEMORY_LCD_DRIVER_FROM_CTX. All file-level globals are gone; nothing in this translation unit now outlives the driver pointer. Signed-off-by: Davide Bettio <davide@uninstall.it>
Fold MonoScreen into struct OLEDDriver as an embedded member and drop the file-static pointer + its separate calloc. The per-screen state now travels with the driver pointer recovered by OLED_DRIVER_FROM_CTX, a prerequisite for multi-instance use. The controller panels are fixed at 128x64 for all three variants, so the MonoScreen dimensions are initialised from the existing DISPLAY_WIDTH / DISPLAY_HEIGHT constants rather than from opts. Signed-off-by: Davide Bettio <davide@uninstall.it>
Generalise the dispatch to drive all three supported controllers from the per-controller OLEDDesc descriptors. A compatible-string lookup replaces the display_type_t enum branching: I2C address, init sequence, per-page column-reset flag, and scanline prefix padding all come from the descriptor. Unknown or missing compatibles now log an ESP_LOGE and early- return instead of silently defaulting to SSD1306, fixing a path that quietly masked typos in the Erlang `compatible` opt. Remove display_type_t, the driver->type field, and the hardcoded I2C_ADDRESS macro -- all three subsumed by the descriptor. Signed-off-by: Davide Bettio <davide@uninstall.it>
git mv ssd1306_display_driver.c -> oled_display_driver.c; rename the create_port entry point and the log TAG accordingly. Pure rename -- all three OLED compatibles (solomon-systech,ssd1306, solomon-systech,ssd1315, sino-wealth,sh1106) now dispatch through oled_display_create_port. The previous filename attributed a Sino Wealth controller (SH1106) to Solomon Systech and was obsolete since the file started driving multiple variants. Signed-off-by: Davide Bettio <davide@uninstall.it>
|
per AMP: PR Review — Branch
|
| File | Line(s) | Allocation |
|---|---|---|
dcs_lcd_display_driver.c |
312, 318-319, 321-322 | calloc(driver), heap_caps_malloc(pixels/pixels_out), heap_caps_malloc(bytes/bytes_out) |
dcs_lcd_commands.c |
64, 88 | heap_caps_malloc(tmpbuf) for DMA transfer |
epaper_display_driver.c |
205, 295, 345 | heap_caps_malloc(buf), malloc(driver) |
oled_display_driver.c |
~118 | malloc(buf) in do_update — leaks items on early return |
On ESP32 with limited heap, heap_caps_malloc(MALLOC_CAP_DMA) can realistically fail.
🟢 P2 — oled_display_driver.c Leaks buf and items on I2C Failure
File: oled_display_driver.c (do_update), around line 124
if (i2c_driver_acquire(driver->i2c_host, &i2c_num, ctx->global) != I2CAcquireOk) {
fprintf(stderr, "Invalid I2C peripheral\n");
return; // leaks: buf, items (and items' owned data)
}Fix:
if (i2c_driver_acquire(driver->i2c_host, &i2c_num, ctx->global) != I2CAcquireOk) {
fprintf(stderr, "Invalid I2C peripheral\n");
+ free(buf);
+ display_items_delete(items, len);
return;
}🟢 P2 — dcs_lcd_draw.c:140 — Misleading Variable Name
uint16_t *pixmem32 = (uint16_t *) ...; // named "32" but is actually 16-bitCarried over from the old st7789_display_driver.c. Trivial rename:
- uint16_t *pixmem32 = (uint16_t *) (((uint8_t *) screen->pixels) + xpos * sizeof(uint16_t));
+ uint16_t *pixmem16 = (uint16_t *) (((uint8_t *) screen->pixels) + xpos * sizeof(uint16_t));(And update the two references at lines 162, 164.)
🟢 P2 — uFont Parser Minimum Size Guard
File: ufontlib.c:602
ufont_parse() reads at offsets 0 and 8 without checking buf_size >= 12:
EpdFont *ufont_parse(const void *iff_binary, int buf_size)
{
+ if (!iff_binary || buf_size < 12) {
+ return NULL;
+ }
if (!ufont_iff_is_valid_ufl(iff_binary)) {
return NULL;
}Design Notes (Non-blocking)
find_max_line_len receives i not items_len — intentional
In all draw modules (dcs_lcd_draw.c:243, epaper_draw.c:308, mono_draw.c:333), the call passes i (current item index) as the length argument:
int max_line_len = below ? 1 : dcs_lcd_find_max_line_len(screen, items, i, xpos, ypos);This is intentional: it scans only items with lower index (higher z-order / painted first) to determine the maximum contiguous pixel run before hitting an overlapping item. The parameter name items_len in the function signature is somewhat misleading but the logic is correct and matches the SDL reference driver.
Duplicate compatible-string tables
display_driver.c duplicates the family-specific compatible tables (dcs_lcd_compat_table, oled_compat_table, epaper_compat_table) as an if/else chain. This creates a maintenance burden — adding a new controller requires editing two places. A future improvement could be a single registration table, but this is fine for now.
context_make_atom helper
display_items.h:31-34 keeps a // TODO: deprecated helper wrapper. Consider removing it and inlining globalcontext_make_atom at call sites as a follow-up.
Summary of Recommendations
| Priority | Issue | Effort |
|---|---|---|
| 🔴 P0 | uFont global state / use-after-free | Medium |
| 🔴 P0 | Uninitialized display items on error paths | Small |
| 🟡 P1 | Silent message loss (queue overflow) | Small |
| 🟡 P1 | Port creation succeeds despite init failure | Medium |
| 🟡 P1 | Pixel write off-by-one (> → >=) |
Trivial |
| 🟢 P2 | Typo comptaible |
Trivial |
| 🟢 P2 | Missing malloc NULL checks | Small |
| 🟢 P2 | OLED do_update leaks on I2C failure | Trivial |
| 🟢 P2 | Misleading pixmem32 name |
Trivial |
| 🟢 P2 | uFont parser min-size guard | Trivial |
Reorganizes AtomGL display drivers into one unified driver per
hardware family, each dispatched via a compatible-string lookup
returning a per-controller descriptor. Bytes-on-the-wire are
unchanged for every previously supported compatible.
Before → After
dcs_lcd_display_driver.c) +DCSLCDDescdescriptor tableepaper_display_driver.c) +EPaperDescdescriptor tableoled_display_driver.c) +OLEDDescdescriptor tableWhat every driver gets for free
clock_speed_hzErlang opt: override the descriptor's defaultSPI clock rate.
width,height,x_offset,y_offset,color_orderErlangopts apply uniformly to every DCS LCD / e-paper / memory LCD
compatible.
init_listErlang-side init override now applies to every DCSLCD and e-paper compatible (extended with
{wait_busy_level, 0|1}for e-paper).path required.
driver's state travels with its
CONTAINER_OF-recoverablestruct.
Hardware validation
Hardware-confirmed on real panels with the demo app and a
regression test scene:
ilitek,ili9341(TFT RGB565)sitronix,st7789(TFT RGB565)waveshare,5in65-acep-7c(7-color e-ink)good-display/gdep073e01(7-color e-ink)sharp,memory-lcd(monochrome SPI)Build-only validation (no panels in the test rig):
solomon-systech,ssd1306,solomon-systech,ssd1315,sino-wealth,sh1106(OLED variants)ilitek,ili9342c,ilitek,ili9486,ilitek,ili9488,sitronix,st7796(DCS LCD variants)For the OLED family, byte-for-byte equivalence of the post-refactor
init sequences was verified via
_Static_assertsize guards on theinit arrays and manual transcription review against the pre-refactor
inline code. Hardware validation on real OLED panels should precede
relying on this driver in production.
Preserved behaviour
compatiblestring still works.blending are unchanged.
Follow-ups (deferred, not blocking)
(SSD1306/SSD1315/SH1106).
descriptor
madctl[]tables carry0xFFsentinels where thepre-refactor drivers didn't support those rotations.
init_listErlang override for OLED (parity with e-paper).already uses this).
validation.
color_order: rgbworkscleanly on ili9341 / ili9342c.
(SDL-style).
(drops a 921×63 glyph from ~227KB to ~29KB).
Test plan
idf.py buildon the full AtomVM tree.Waveshare 5.65", GDEP073E01, Sharp memory LCD) with the demo
app and the regression test scene.
flagged above.