Skip to content

feat(baseui): tier the emote set by flash class - #11257

Merged
thebentern merged 1 commit into
promicro-exclude-emojifrom
emoji-tiers
Jul 27, 2026
Merged

feat(baseui): tier the emote set by flash class#11257
thebentern merged 1 commit into
promicro-exclude-emojifrom
emoji-tiers

Conversation

@thebentern

@thebentern thebentern commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Stacked on #11256 — base it at promicro-exclude-emoji so the diff shows only the tiering. Retarget to develop once that merges.

Why

The BaseUI emote table is 146 entries over 103 unique 16x16 bitmaps, and today it's all-or-nothing: EXCLUDE_EMOJI, or the lot. On tight targets that's a 6.8 KB cliff — which is exactly why #11256 has nrf52_promicro_diy_tcxo giving up emoji entirely to fit under the warm-store region. There was no way to say "keep 👍 and ⚠️, drop the moon phases."

What

Four ordinal levels, gated per section so picker order doesn't shuffle as tiers drop out:

level contents
EMOTE_SET_NONE nothing; emoji render as their text label
EMOTE_SET_CORE thumbs, question/alert, symbols, heart
EMOTE_SET_STANDARD + smileys, laughing, gestures, misc faces, weather
EMOTE_SET_FULL + moon phases, objects, arrows, Halloween, holidays

Measured on rak4631:

level image end vs FULL
FULL (today) 0xE46D8
STANDARD 0xE3BC0 −2,840
CORE 0xE30E0 −5,624
NONE 0xE2C40 −6,808

Only the table is gated, not the ~103 bitmap definitions. Dropped entries leave their bitmaps unreferenced and -fdata-sections/--gc-sections discards them, so a tier costs one #if per section instead of a gate per bitmap. Verified at symbol level — an EMOTE_SET_CORE image keeps graphics::thumbup, question, heart, check_mark and has dropped smiling_eyes, sun, new_moon, jack_o_lantern, turkey, bowling, christmas_tree.

Why a new flash ladder instead of MESHTASTIC_MEM_CLASS

This is the part worth arguing with me about. Emote bitmaps are PROGMEM — they cost zero RAM — so keying them off the RAM ladder would be measuring the wrong resource, and the two genuinely disagree: classic ESP32 and nRF52840 are both MEM_CLASS_SMALL, but the ESP32 has well over twice the app flash. A RAM-keyed default would trim the wrong boards.

So this adds MESHTASTIC_FLASH_CLASS (src/memory/FlashClass.h) as the sibling ladder that MemClass.h already gestures at when it calls MAX_NUM_NODES "deliberately unclassed (flash-shaped)". It's written to be reusable for other flash-shaped decisions later.

A class is a default, not a verdict — rak4631 and promicro are the same chip and the same FLASH_CLASS_SMALL, yet one has ~22 KB of headroom and the other doesn't fit at all. Variants override with -D MESHTASTIC_EMOTE_SET, as promicro does here.

Behavior change to weigh

FLASH_CLASS_SMALL (nRF52840) defaults to STANDARD, so every nRF52 board loses moon phases, objects, arrows and the seasonal sets for 2,840 bytes. I picked that because nRF52840 is the tightest screen-capable region we ship and rak4631 already sits at ~97% of it on develop — but it's a one-line change to leave nRF52 on FULL if you'd rather only promicro pay. ESP32/RP2040 and above are unchanged at FULL.

EXCLUDE_EMOJI still works and maps to EMOTE_SET_NONE. InkHUD is unaffected — it already excludes graphics/emotes.cpp from its build.

Verification

  • All four levels build clean on rak4631; nrf52_promicro_diy_tcxo lands at 0xE8618, byte-identical to the EXCLUDE_EMOJI build it replaces.
  • static_assert catches a mis-gated section that would otherwise silently ship an empty picker.
  • Native suite (Docker): 784 cases, 781 pass. The 2 failures (test_B11_normal_unicast_still_uses_pki, test_B12_licensed_receiver_does_not_decrypt_pki) reproduce identically on pristine develop @ 1e982fa and are unrelated to this change — worth a separate look, they came in with Sign plaintext packets in licensed mode #10969.

Summary by CodeRabbit

  • New Features

    • Added tiered emote sets that automatically adjust to device flash capacity.
    • Added support for core, standard, and full emote collections on compatible devices.
    • Added safeguards to prevent an empty emote picker from being built accidentally.
  • Improvements

    • Devices with limited storage now exclude larger emote collections to preserve available space.
    • Existing emoji exclusion behavior remains supported.

The BaseUI emote table is 146 entries over 103 unique 16x16 bitmaps, and it
was all-or-nothing: EXCLUDE_EMOJI or the lot. On the tightest targets that
made it a 6.8 KB cliff, which is how nrf52_promicro_diy_tcxo ended up giving
up emoji entirely to fit under the warm-store region.

Split it into four ordinal levels - NONE, CORE, STANDARD, FULL - gated per
section so picker order is unchanged as tiers drop out. Measured on rak4631:

  FULL      0xE46D8   (todays behavior)
  STANDARD  0xE3BC0   -2,840
  CORE      0xE30E0   -5,624
  NONE      0xE2C40   -6,808

Only the table is gated. Dropped entries leave their bitmaps unreferenced and
-fdata-sections/--gc-sections discards them, so a tier costs one #if per
section rather than a gate per bitmap. Verified at symbol level: an
EMOTE_SET_CORE image keeps graphics::thumbup/question/heart/check_mark and
has dropped smiling_eyes, sun, new_moon, jack_o_lantern and the rest.

The level is pegged to a new MESHTASTIC_FLASH_CLASS (memory/FlashClass.h),
deliberately NOT to MESHTASTIC_MEM_CLASS. Emote bitmaps are PROGMEM and cost
zero RAM, and the two resources genuinely disagree: classic ESP32 and
nRF52840 are both MEM_CLASS_SMALL, but the ESP32 has over twice the app
flash, so a RAM-keyed default would trim the wrong boards. FlashClass is the
sibling ladder MemClass.h already gestures at when it calls MAX_NUM_NODES
"deliberately unclassed (flash-shaped)".

Defaults: FLASH_CLASS_SMALL (nRF52840) gets STANDARD, everything MEDIUM and
above keeps FULL, TINY gets NONE. That is a real behavior change for nRF52 -
it trades moon phases, objects, arrows and the seasonal sets for 2.8 KB on a
class where rak4631 already sits at 97% of its region on develop. Variants
override with -D MESHTASTIC_EMOTE_SET, as promicro now does.

EXCLUDE_EMOJI still works and maps to EMOTE_SET_NONE.

InkHUD is unaffected: it excludes graphics/emotes.cpp from its build.
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change introduces flash-class-based emote tiers, applies those tiers to bitmap declarations and emote-table entries, adds a non-empty-table assertion, and configures the nRF52 Pro Micro TCXO variant to build with no emotes.

Changes

Emote tier selection

Layer / File(s) Summary
Flash-class selection
src/memory/FlashClass.h
Defines flash-class constants and derives MESHTASTIC_FLASH_CLASS from target configuration.
Emote-set contract
src/graphics/emotes.h
Defines emote tiers, selects MESHTASTIC_EMOTE_SET, and gates bitmap declarations accordingly.
Emote table gating
src/graphics/emotes.cpp, variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini
Conditionally compiles emote groups by tier, asserts enabled tables are non-empty, and selects EMOTE_SET_NONE for the nRF52 variant.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: ixitxachitl

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: tiering the emote set by flash class.
Description check ✅ Passed The description is detailed and covers motivation, behavior, impact, and verification, but it omits the template's attestation checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch emoji-tiers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/memory/FlashClass.h (1)

3-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Trim oversized C++ comment blocks.

Both headers add multi-line narrative comments where the macro names and concise contract comments are sufficient.

  • src/memory/FlashClass.h#L3-L24: reduce the block to the flash-vs-RAM distinction and override behavior.
  • src/graphics/emotes.h#L6-L19: reduce the block to flash-based tier selection and independent section gating.

As per coding guidelines: “Keep code comments minimal—one or two lines maximum.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/memory/FlashClass.h` around lines 3 - 24, Trim the narrative comment
block in src/memory/FlashClass.h lines 3-24 to one or two lines covering only
the flash-versus-RAM distinction and that variants may override the default.
Also shorten the comment block in src/graphics/emotes.h lines 6-19 to one or two
lines describing flash-based tier selection and independent section gating; do
not change the macro logic.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/graphics/emotes.cpp`:
- Around line 10-14: Update the emotes[] definition in src/graphics/emotes.cpp
to provide a one-element placeholder array when MESHTASTIC_EMOTE_SET is
EMOTE_SET_NONE, while keeping numEmotes equal to 0 for that branch. Preserve the
existing emote table for all non-empty tiers so the static assertion and normal
counts remain unchanged.

---

Nitpick comments:
In `@src/memory/FlashClass.h`:
- Around line 3-24: Trim the narrative comment block in src/memory/FlashClass.h
lines 3-24 to one or two lines covering only the flash-versus-RAM distinction
and that variants may override the default. Also shorten the comment block in
src/graphics/emotes.h lines 6-19 to one or two lines describing flash-based tier
selection and independent section gating; do not change the macro logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf4fc9f9-cdad-4041-be06-73a33ac3a8bf

📥 Commits

Reviewing files that changed from the base of the PR and between 4bb474a and 0a68dee.

📒 Files selected for processing (4)
  • src/graphics/emotes.cpp
  • src/graphics/emotes.h
  • src/memory/FlashClass.h
  • variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini

Comment thread src/graphics/emotes.cpp
Comment on lines +10 to +14
#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_CORE
// --- Thumbs ---
{"\U0001F44D", thumbup, thumbs_width, thumbs_height}, // 👍 Thumbs Up
{"\U0001F44E", thumbdown, thumbs_width, thumbs_height}, // 👎 Thumbs Down
#endif // EMOTE_SET_CORE

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -eu

tmp="$(mktemp --suffix=.cpp)"
trap 'rm -f "$tmp"' EXIT

cat >"$tmp" <<'EOF'
struct Emote {};
const Emote emotes[] = {};
EOF

"${CXX:-c++}" -std=c++17 -pedantic-errors -fsyntax-only "$tmp"

Repository: meshtastic/firmware

Length of output: 199


🏁 Script executed:

#!/usr/bin/env bash
set -eu

echo "CXX availability:"
command -v c++ || true
command -v clang++ || true
command -v g++ || true

echo
echo "Relevant files:"
fd -a 'emotes.cpp|platformio.ini' . | sed 's#^\./##' | head -100

echo
echo "Search for MESHTASTIC_EMOTE_SET definitions/usages:"
rg -n "MESHTASTIC_EMOTE_SET|EMOTE_SET_NONE|enum.*Emote|enum class Emote|struct Emote|const Emote emotes" .

Repository: meshtastic/firmware

Length of output: 9453


🏁 Script executed:

#!/usr/bin/env bash
set -eu

echo "emotes.cpp first 35 lines:"
sed -n '1,35p' src/graphics/emotes.cpp | cat -n

echo
echo "emotes.cpp lines 217-235:"
sed -n '217,235p' src/graphics/emotes.cpp | cat -n

echo
echo "emotes.h relevant section:"
sed -n '40,55p' src/graphics/emotes.h | cat -n

echo
echo "clang C++17 compile test for unknown-bound empty aggregate initializer:"
tmp="$(mktemp --suffix=.cpp)"
trap 'rm -f "$tmp"' EXIT
cat >"$tmp" <<'EOF'
struct Emote {
    const char* label;
};
const Emote emotes[] = {};
EOF
if command -v clang++ >/dev/null 2>&1; then
  clang++ -std=c++17 -pedantic-errors -fsyntax-only "$tmp" || true
fi

echo
echo "clang C++17 compile test for bounded empty aggregate initializer:"
tmp2="$(mktemp --suffix=.cpp)"
trap 'rm -f "$tmp2"' EXIT
cat >"$tmp2" <<'EOF'
struct Emote {
    const char* label;
};
const Emote emotes[1] = {};
EOF
if command -v clang++ >/dev/null 2>&1; then
  clang++ -std=c++17 -pedantic-errors -fsyntax-only "$tmp2" || true
fi

Repository: meshtastic/firmware

Length of output: 4519


Fix the empty emotes[] definition for EMOTE_SET_NONE.

With MESHTASTIC_EMOTE_SET=EMOTE_SET_NONE, every initializer is removed, leaving an unknown-bound empty array declaration that fails before numEmotes or the static assertion are reached. Use a placeholder ONE-element array for the NONE branch and keep numEmotes at 0; use the current table for non-empty tiers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/graphics/emotes.cpp` around lines 10 - 14, Update the emotes[] definition
in src/graphics/emotes.cpp to provide a one-element placeholder array when
MESHTASTIC_EMOTE_SET is EMOTE_SET_NONE, while keeping numEmotes equal to 0 for
that branch. Preserve the existing emote table for all non-empty tiers so the
static assertion and normal counts remain unchanged.

@github-actions

Copy link
Copy Markdown
Contributor

⚡ Try this PR in the Web Flasher

Note

Building this pull request… the flash button, badges and supported-board
list will appear here automatically once CI finishes.

@thebentern thebentern added bugfix Pull request that fixes bugs cleanup Code cleanup or refactor labels Jul 27, 2026
@thebentern
thebentern merged commit ca252e8 into promicro-exclude-emoji Jul 27, 2026
8 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Pull request that fixes bugs cleanup Code cleanup or refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant