fix(promicro): exclude emoji to fit under the warm-store region (#11256)

nrf52_promicro_diy_tcxo has been failing the nrf52 warm-region guard on
develop: the image ends at 0xEA0C0, 192 bytes past the 12 KB WarmNodeStore
record-ring reserved at 0xEA000. This variant compiles four radio driver
families (SX126x/LLCC68, SX127x/RF95, LR11x0/LR1121, LR2021) so any module
can be soldered on, which makes it the largest nrf52 image we ship.

Building it with -D EXCLUDE_EMOJI saves 6,808 bytes and puts the image at
0xE8618, 6.6 KB clear of the warm region.

EXCLUDE_EMOJI was not previously usable: graphics::emotes[] becomes empty,
but the canned-message emote picker never checked for that. Entering the
picker clamped emotePickerIndex to numEmotes - 1 (i.e. -1), and selecting
read emotes[-1].label into a String - an out-of-bounds read of whatever
precedes the array in flash. Guard both entry points instead: refuse to
open the picker when there are no emotes, and bounce back to freetext if
the picker state is somehow reached anyway.

Under whole-image LTO those guards fold to constants, so the picker draw
and input paths dead-strip entirely on builds that set EXCLUDE_EMOJI -
which is where the savings come from beyond the bitmap data itself.

Received messages containing emoji render as text on this variant, and
the emote-list key is a no-op. Verified rak4631 (emoji enabled) is
unaffected: 0xE46D8, 22 KB clear.
This commit is contained in:
Ben Meadors
2026-07-27 15:20:57 +00:00
committed by GitHub
co-authored by GitHub
parent a640d44b5c
commit f61f65891c
2 changed files with 10 additions and 2 deletions
+9 -2
View File
@@ -880,8 +880,10 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
// All hardware keys fall through to here (CardKB, physical, etc.)
if (event->kbchar == INPUT_BROKER_MSG_EMOTE_LIST) {
updateState(CANNED_MESSAGE_RUN_STATE_EMOTE_PICKER);
screen->forceDisplay();
if (graphics::numEmotes > 0) { // no picker on EXCLUDE_EMOJI builds (empty emotes[])
updateState(CANNED_MESSAGE_RUN_STATE_EMOTE_PICKER);
screen->forceDisplay();
}
return true;
}
// Confirm select (Enter)
@@ -965,6 +967,11 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
int CannedMessageModule::handleEmotePickerInput(const InputEvent *event)
{
int numEmotes = graphics::numEmotes;
if (numEmotes == 0) { // EXCLUDE_EMOJI: emotes[] is empty, any index would read out of bounds
updateState(CANNED_MESSAGE_RUN_STATE_FREETEXT, true);
screen->forceDisplay();
return 1;
}
// Override isDown and isSelect ONLY for emote picker behavior
bool isUp = isUpEvent(event);
@@ -15,6 +15,7 @@ board = promicro-nrf52840
build_flags = ${nrf52840_base.build_flags}
-I variants/nrf52840/diy/nrf52_promicro_diy_tcxo
-D NRF52_PROMICRO_DIY
-D EXCLUDE_EMOJI ; this variant builds 4 radio driver families and is the largest nrf52 image; emote bitmaps don't fit under the 0xEA000 warm-store cap
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/diy/nrf52_promicro_diy_tcxo>
debug_tool = jlink