Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
6270b3f
feat(screen): stream framebuffer to the client as FromRadio display_f…
jamesarich Aug 31, 2026
1c484ff
fix(screen): harden mirror from adversarial review
jamesarich Aug 31, 2026
dd36628
feat(screen): stream the TFT color-region palette for color-accurate …
jamesarich Aug 31, 2026
c4110dd
fix(screen): capture the mirror palette at paint time, not after the …
jamesarich Aug 31, 2026
ec725c7
fix(screen): pre-PR review fixes for the mirror
jamesarich Aug 31, 2026
af8dfa7
feat(screen): stream MUI dirty rects as RGB565 DisplayFrames
jamesarich Aug 31, 2026
7a641a4
fix(screen): size the MUI rect pool for a full repaint
jamesarich Aug 31, 2026
c840bc1
fix(screen): gate the MUI flush-observer registration on MESHTASTIC_M…
jamesarich Aug 31, 2026
a4e7103
feat(screen): bridge InputBroker events into MUI
jamesarich Aug 31, 2026
87f9df5
fix(screen): route remote input to MUI directly, not through the Inpu…
jamesarich Aug 31, 2026
20877eb
feat(metadata): report DisplayInfo on MUI builds
jamesarich Aug 31, 2026
46119ab
fix(screen): map remote directions onto MUI's trackball semantics
jamesarich Aug 31, 2026
f2cf1f1
fix(screen): repair MUI mirror lifetime, ownership, and backpressure
jamesarich Aug 31, 2026
9973d3d
fix(screen): drop the spike-local device-ui override from the branch
jamesarich Sep 1, 2026
07cfb8f
fix(screen): compile the MUI mirror out unless it is opted into
jamesarich Sep 1, 2026
62d6d4c
fix(screen): report the real panel class, not TFT for everything
jamesarich Sep 1, 2026
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
18 changes: 18 additions & 0 deletions src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define HAS_SCREEN 0
#endif

// Display mirroring to the client (FromRadio.display_frame) rides the screen
// and can be excluded independently with MESHTASTIC_EXCLUDE_SCREEN_MIRROR.
#if HAS_SCREEN && !defined(MESHTASTIC_EXCLUDE_SCREEN_MIRROR)
#define HAS_SCREEN_MIRROR 1
#else
#define HAS_SCREEN_MIRROR 0
#endif

// Mirroring MUI (device-ui/LVGL) streams RGB565 dirty rects instead of the
// 1bpp framebuffer, and needs a device-ui carrying the flush observer. Until
// that lands upstream the whole path - queue, pool and input seam - compiles
// out, so a color build that does not opt in carries none of it.
#if HAS_SCREEN_MIRROR && HAS_TFT && defined(MESHTASTIC_MUI_MIRROR)
#define HAS_MUI_MIRROR 1
#else
#define HAS_MUI_MIRROR 0
#endif

#ifndef USE_ETHERNET_DEFAULT
#define USE_ETHERNET_DEFAULT 0
#endif
Expand Down
4 changes: 4 additions & 0 deletions src/graphics/HUB75Display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#if defined(USE_HUB75)

#include "HUB75Display.h"
#include "ScreenMirror.h"
#include "TFTColorRegions.h"
#include "TFTPalette.h"
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
Expand Down Expand Up @@ -121,6 +122,9 @@ void HUB75Display::display()
firstFrame = false;
#if GRAPHICS_TFT_COLORING_ENABLED
lastColorSig = colorSig;
#if HAS_SCREEN_MIRROR
graphics::screenMirror.capturePalette(colorSig, onBe, offBe, graphics::colorRegions, graphics::getTFTColorRegionCount());
#endif
// Regions are re-registered every frame by the renderers; clear so they
// don't accumulate across frames.
graphics::clearTFTColorRegions();
Expand Down
16 changes: 16 additions & 0 deletions src/graphics/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "Screen.h"
#include "NodeDB.h"
#include "PowerMon.h"
#include "ScreenMirror.h"
#include "Throttle.h"
#include "configuration.h"
#include "meshUtils.h"
Expand Down Expand Up @@ -181,6 +182,18 @@ static void drawLockdownLockScreen(OLEDDisplay *display)
}
#endif

// Give ScreenMirror a look at the committed framebuffer (no-op unless armed).
// Deliberately scoped to updateUiFrame commits: the few direct display()
// paths it bypasses (EInk re-commits, boot logo) immediately follow or
// precede a mirrored frame.
static inline void screenMirrorCapture()
{
#if HAS_SCREEN_MIRROR
if (screen)
screenMirror.onRendered(screen->getDisplayDevice());
#endif
}

static inline void updateUiFrame(OLEDDisplayUi *ui)
{
#ifdef MESHTASTIC_LOCKDOWN
Expand Down Expand Up @@ -208,13 +221,16 @@ static inline void updateUiFrame(OLEDDisplayUi *ui)
NotificationRenderer::drawBannercallback(display, ui->getUiState());
}
display->display();
// The mirror sees the LOCKED frame, matching the panel's redaction.
screenMirrorCapture();
return;
}
#endif
#if GRAPHICS_TFT_COLORING_ENABLED
prepareFrameColorRegions();
#endif
ui->update();
screenMirrorCapture();
}
// Global variables for alert banner - explicitly define with extern "C" linkage to prevent optimization

Expand Down
Loading
Loading