Add a shared spectrum-analyzer plot component - #2755
Open
vnxdtzip wants to merge 2 commits into
Open
Conversation
added 2 commits
August 4, 2026 19:54
#### Proposed Changes ####
A module that needs a dimmed or highlighted shade of the active theme has no
way to ask for one. The only helper available, getColorVariation, steps
brightness up or down and cannot mix toward another colour, so modules fall
back to a fixed constant such as TFT_DARKGREY or TFT_WHITE. That is the root
cause of most of the screens in Bruce that stop following the user's theme as
soon as they need more than the primary colour.
This adds two helpers next to it in core/display:
blendColors(a, b, t) linear RGB565 mix; t = 0 keeps a, t = 255 keeps b
buildHeatPalette(lut, n) fills a lookup table with a theme ramp running
from the background up to a brightened primary,
for waterfalls and other intensity plots
Both are pure additions. No existing function is modified, and nothing calls
them in this PR - the modules that consume them follow separately.
#### Types of Changes ####
New Feature (internal helper API). No behaviour change and no breaking change.
#### Verification ####
Nothing on screen changes from this PR alone, so verification is limited to
confirming the build is clean and that only insertions were made:
pio run -e m5stack-cardputer
git show --stat # 2 files changed, 31 insertions(+), 0 deletions(-)
#### Testing ####
Bruce has no unit test harness covering the display layer, so this was
verified by compiling for m5stack-cardputer on this branch. The helpers get
exercised on hardware through the follow-up PRs that use them.
#### Linked Issues ####
None. This is the base commit of a series that standardises the
spectrum-style screens; the module PRs listed below depend on it.
#### User-Facing Change ####
```release-note
NONE
```
#### Further Comments ####
Prerequisite for ui/spectrum-view, ui/rf-waterfall-theme and
ui/rf-spectrum-theme.
#### Proposed Changes ####
Every "signal strength across a band" screen in Bruce draws its own bars,
picks its own colours and hardcodes its own geometry. No two look alike, and
none of them scale past the panel the original author happened to own.
This adds SpectrumPlot (core/spectrum_plot), which owns the whole
presentation for that shape of data:
- layout derived from tftWidth/tftHeight, degrading on short screens by
dropping the ruler first, then the status line, then the waterfall
- filled trace with a peak-hold line, an animated noise floor and a dashed
reference grid visible only through the empty sky
- scrolling waterfall backed by a ring of rendered rows
- labelled ruler and a status line
- every colour derived from the active theme through blendColors
Callers keep their own radio and fill an envelope of width() values in 0-100;
the component owns every pixel. Each pixel of the band is written exactly once
per frame, so the animation is flicker free without needing a full-screen
sprite.
WifiSpectrumView (modules/wifi/wifi_spectrum) sits on top and maps the 2.4GHz
channels onto a real frequency axis as overlapping spectral lobes, so the
22MHz overlap between neighbours becomes visible and a sweep reads as one
continuous trace. It also eases the drawn levels toward the measured ones, so
the trace glides rather than snapping channel by channel.
Nothing uses either component in this PR; the modules move over separately.
#### Types of Changes ####
New Feature (internal UI component). No behaviour change and no breaking
change on its own.
#### Verification ####
Nothing on screen changes from this PR alone. The component becomes visible
through ui/channel-analyzer-spectrum, ui/jam-detect-spectrum and
ui/nrf-spectrum, which is where the rendering should be judged.
pio run -e m5stack-cardputer
git show --stat # 4 new files, 445 insertions(+), 0 deletions(-)
#### Testing ####
No unit test harness exists for this layer. Both files were compiled for
m5stack-cardputer as part of ui/channel-analyzer-spectrum, which stacks
directly on this branch and builds clean; this branch was not built in
isolation. Rendering has not yet been checked on hardware by me - a reviewer
with a device should confirm the layout on a non-240x135 panel in particular,
since the degradation path for short screens is the least exercised part.
#### Linked Issues ####
None. Depends on ui/color-helpers for blendColors and buildHeatPalette.
#### User-Facing Change ####
```release-note
NONE
```
#### Further Comments ####
Memory cost is one calloc of wfRows * plotW bytes for the waterfall history
(about 5KB on a 240px panel) plus two envelope buffers of plotW bytes each,
all freed on exit. If the waterfall allocation fails the component degrades to
a plot without history rather than refusing to start.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed Changes
Every "signal strength across a band" screen in Bruce draws its own bars,
picks its own colours and hardcodes its own geometry. No two look alike, and
none of them scale past the panel the original author happened to own.
This adds SpectrumPlot (core/spectrum_plot), which owns the whole
presentation for that shape of data:
dropping the ruler first, then the status line, then the waterfall
reference grid visible only through the empty sky
Callers keep their own radio and fill an envelope of width() values in 0-100;
the component owns every pixel. Each pixel of the band is written exactly once
per frame, so the animation is flicker free without needing a full-screen
sprite.
WifiSpectrumView (modules/wifi/wifi_spectrum) sits on top and maps the 2.4GHz
channels onto a real frequency axis as overlapping spectral lobes, so the
22MHz overlap between neighbours becomes visible and a sweep reads as one
continuous trace. It also eases the drawn levels toward the measured ones, so
the trace glides rather than snapping channel by channel.
Nothing uses either component in this PR; the modules move over separately.
Types of Changes
New Feature (internal UI component). No behaviour change and no breaking
change on its own.
Verification
Nothing on screen changes from this PR alone. The component becomes visible
through ui/channel-analyzer-spectrum, ui/jam-detect-spectrum and
ui/nrf-spectrum, which is where the rendering should be judged.
Testing
No unit test harness exists for this layer. Both files were compiled for
m5stack-cardputer as part of ui/channel-analyzer-spectrum, which stacks
directly on this branch and builds clean; this branch was not built in
isolation. Rendering has not yet been checked on hardware by me - a reviewer
with a device should confirm the layout on a non-240x135 panel in particular,
since the degradation path for short screens is the least exercised part.
Linked Issues
None. Depends on #2754 (ui/color-helpers) for blendColors and buildHeatPalette.
User-Facing Change
Further Comments
Memory cost is one calloc of wfRows * plotW bytes for the waterfall history
(about 5KB on a 240px panel) plus two envelope buffers of plotW bytes each,
all freed on exit. If the waterfall allocation fails the component degrades to
a plot without history rather than refusing to start.