Skip to content

Dev - #129

Merged
anarchyysm merged 104 commits into
mainfrom
dev
Aug 20, 2026
Merged

Dev#129
anarchyysm merged 104 commits into
mainfrom
dev

Conversation

@anarchyysm

@anarchyysm anarchyysm commented Aug 20, 2026

Copy link
Copy Markdown
Member

Description

Please include a summary of the changes and which issue is fixed. List any dependencies that are required for this change.

Related Issue: Fixes # (issue)


Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

Checklist

  • I have read the CONTRIBUTING.md document.
  • My code follows the style guidelines of this project.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have made corresponding changes to the documentation.
  • My changes generate no new warnings during build.
  • I have tested this change on physical hardware. (Please specify which target below)

Hardware Testing Details

  • Target: (e.g., ESP32-C5)
  • Environment: (e.g., ESP-IDF v5.3)
  • Test Result: (e.g., Successfully decoded and transmitted subghz signals)

anarchyysm and others added 30 commits August 17, 2026 16:11
Enable the build/config toggles the rest of this work depends on:
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY (large static .bss -> PSRAM),
CONFIG_TINYUSB_MSC_* (expose the SD as a USB drive), the LVGL image
decoders (GIF/TJPGD/lodepng), and CONFIG_COMPILER_OPTIMIZATION_PERF (-O2)
for the CPU-bound software renderer. -O2 + IDF's -Werror=all turns a few
pre-existing patterns into hard errors, so demote just the noisy -O2
analysis classes (stringop-truncation/-overflow, format-truncation,
array-bounds, maybe-uninitialized) to warnings in the top CMakeLists.
idf_component.yml gains the esp_tinyusb dependency for MSC.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Memory-safety + concurrency fixes in the P4 phoneapis (BLE runs on the C5;
the P4 bridges frames over SPI on RADIO-core tasks).

MeshCore: DEVICE_INFO response buffer resp[80] -> resp[82] (payload is
exactly 82 bytes, written out of bounds on every connect); mutex around the
offline queue (mutated by 3 RADIO-core tasks); clamp the phone-supplied
out_path_len before the fixed-buffer copy.

Meshtastic: encode the protobuf field tag as a varint (a 1-byte tag is
malformed for field numbers >=16, desyncing the handshake); add an FSM mutex
across the two RADIO-core tasks; notify_task stack 4096 -> 8192.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Internal DRAM was critically low (~19 KB free at boot; OOM restarts):
libApplications.a .bss pinned the scarce internal heap with per-screen
static list/DB buffers reserved even with their screen closed. Prefix the
big CPU-only string/list/DB arrays with EXT_RAM_BSS_ATTR so they live in
PSRAM (200 MHz octal) instead of internal DMA RAM. NFC card-emulation
buffers are deliberately kept internal (timing-critical RF response path).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…hook

Re-enable .double_buffer and a 1/4-screen strip (freed now that static
buffers moved to PSRAM) so a full redraw lands as one smooth top-to-bottom
sweep instead of stepped strips. Add the lvgl_glue_direct_* trans-done
semaphore path so a full-screen app (the Game Boy emulator) can drive the
panel directly without corrupting frames; the shared color-trans-done ISR
replicates esp_lvgl_port's flush-ready in normal mode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Read the color format from the .bin header and load via the LVGL draw-buf
layout, so both ARGB8888 and RGB565A8 assets decode correctly (strict no-op
for the current ARGB8888 assets). Removes the hardcoded ARGB8888 assumption.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Peanut-GB core + HighBoy platform layer: recursive SD ROM discovery,
fullscreen landscape blit over an internal DMA strip (waits on the LVGL
trans-done semaphore so single-buffer reuse is safe), 60 Hz pacing with
video frame-drop, battery .sav persistence, audio via minigb_apu, and a
graceful BACK-hold exit that tears down and returns to the games menu
without a reboot. peanut_gb.h / minigb_apu.* are vendored 3rd-party.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fullscreen image viewer with a slim header/footer: JPEG via TJPGD (file
path), PNG via lodepng, GIF via lv_gif; fit-to-screen without upscaling
small media. Launched from the Files browser (files_ui routing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MP4 player screen, an ISO-BMFF metadata parser (codec/cover art), and a
shared media thumbnail decoder.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New MP3 decode/playback screen and an ID3v2 (v2.2/2.3/2.4) tag parser
(title/artist/album/year + embedded cover). The library lists WAV and MP3
together and routes prev/next + auto-advance across both players. Players
seed and persist the firmware master volume.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Turn the device into a USB drive to drop firmware/media onto the SD without
a card reader: detach the app FAT -> expose the raw card over TinyUSB MSC
(added to the native USB composite descriptor) -> restore on exit (graceful,
no forced reboot). New screen under the Files menu.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make DOWN consistently descend, move favorite onto a labelled hold gesture,
and add on-screen hints (down = Apps, hold = Config) with adjusted spacing
so the hint no longer overlaps the app icons. Home's idle float animation is
retained.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Radio/worker tasks on SYS_CORE_RADIO called lv_async_call directly; under
LV_OS_NONE that creates an lv_timer while the render thread runs
lv_timer_handler, racing LVGL's global timer list -> corruption / visual
glitches under radio traffic. Add ui_async_call() (recursive UI mutex +
lv_async_call + release), safe from any thread and serialized against the
renderer, and route the cross-thread call sites through it (drops the update
only if the lock times out; no behaviour change).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-arm

Under RF noise on 915 MHz the SX1262 fires continuous CRC/Header-error
RxDone events; each was logged at I/W and re-armed RX, saturating the log
tee (forwarded over BLE/SPI on SYS_CORE_RADIO) and the SPI3 bus shared with
the ST7789 display -> renderer stall / SPI-collision. Demote the
per-noise-packet logs I/W -> D (compile out at INFO), and drop the redundant
sx1262_receive_continuous() re-arm on CRC/Header errors in Meshtastic
on_rx_done (the chip stays in RX-continuous anyway, matching MeshCore).

Note: the structural fix — a shared SPI3 bus lock between the SX1262 HAL and
the ST7789 panel so a radio transfer never overlaps a display flush — is
still pending.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace hardcoded hex colors across the screens with current_theme.* /
UI_COL_* semantic tokens; add the shared token header (ui_semantic.h) and
the theme text-secondary field so screens follow the active theme instead of
baked-in colors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SPI3 is shared by the LoRa radio (SX1262, manual-CS + spi_device_acquire_bus)
and the display (ST7789, esp_lcd queued/DMA). Under sustained RX the radio
could starve the display flush -> LVGL renderer stall -> controlled restart.
Add a shared SPI3 bus lock (binary semaphore, ISR-giveable) in the spi
component: the radio HAL takes/gives it around its transactions and the LVGL
flush holds it from FLUSH_START to the color-trans-done ISR. The flush take is
bounded (50 ms) so a busy radio can never stall the renderer — on timeout it
draws anyway, since the ESP-IDF per-bus lock still serializes the transfer.
max_transfer_sz raised to 49152 so each flush is a single transaction (one
completion per flush, balanced take/give).
The companion connect screen flipped to "linked" on the raw BLE link
(ble_connected), which happens before pairing — so it claimed connected the
moment the PIN would appear, and the PIN was never shown. Add _is_subscribed()
to both phone bridges (reads ble_subscribed, set after encryption + the app
subscribing) and point the UI-only lora_session_app_connected() at it, leaving
the internal _is_connected() untouched. Show the MeshCore pairing PIN on the
"Waiting for app" screen (the P4 owns that PIN). Meshtastic's passkey is random
on the C5 and not yet bridged, so no PIN is shown there.
Relocate components/gameboy -> components/Applications/gameboy so the emulator
lives with the other apps. It stays its own component (keeps its -O2 -w /
ENABLE_SOUND build flags and peanut_gb.h private include); since IDF only
auto-discovers components one level under components/, point EXTRA_COMPONENT_DIRS
at components/Applications so it is still registered. Only gameboy/ there has a
CMakeLists.txt, so no other Applications subdir is affected.
anarchyysm and others added 29 commits August 19, 2026 20:42
@anarchyysm
anarchyysm merged commit 6172980 into main Aug 20, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants