diff --git a/src/graphics/emotes.cpp b/src/graphics/emotes.cpp index 9fb26fa1fdd..6dcc0f85e85 100644 --- a/src/graphics/emotes.cpp +++ b/src/graphics/emotes.cpp @@ -7,11 +7,13 @@ namespace graphics // Always define Emote list and count const Emote emotes[] = { -#ifndef EXCLUDE_EMOJI +#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 +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_STANDARD // --- Smileys (Multiple Unicode Aliases) --- {"\U0001F60A", smiling_eyes, smiling_eyes_width, smiling_eyes_height}, // 😊 Smiling Eyes {"\U0001F600", grinning, grinning_width, grinning_height}, // 😀 Grinning Face @@ -24,13 +26,17 @@ const Emote emotes[] = { {"\U0001F976", cold_face, cold_face_width, cold_face_height}, // 🥶 Cold Face {"\U0001F629", weary_face, weary_face_width, weary_face_height}, // 😩 Weary Face {"\U0001F62E", open_mouth, open_mouth_width, open_mouth_height}, // 😮 Open Mouth +#endif // EMOTE_SET_STANDARD +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_CORE // --- Question/Alert --- {"\u2753", question, question_width, question_height}, // ❓ Question Mark {"\u203C\uFE0F", bang, bang_width, bang_height}, // ‼️ Double Exclamation Mark {"\u26A0\uFE0F", caution, caution_width, caution_height}, // ⚠️ Warning Sign {"\U0001F4F6", antenna_bars, antenna_bars_width, antenna_bars_height}, // 📶 Antenna Bars +#endif // EMOTE_SET_CORE +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_STANDARD // --- Laughing Faces --- {"\U0001F602", haha, haha_width, haha_height}, // 😂 Face with Tears of Joy {"\U0001F923", rofl, rofl_width, rofl_height}, // 🤣 Rolling on the Floor Laughing @@ -44,7 +50,9 @@ const Emote emotes[] = { {"\U0001F634", sleeping_face, sleeping_face_width, sleeping_face_height}, // 😴 Sleeping Face {"\U0001F440", eyes, eyes_width, eyes_height}, // 👀 Eyes {"\U0001F441\uFE0F", eye, eye_width, eye_height}, // 👁️ Eye +#endif // EMOTE_SET_STANDARD +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_STANDARD // --- Gestures and People --- {"\U0001F44B", wave_icon, wave_icon_width, wave_icon_height}, // 👋 Waving Hand {"\u270C\uFE0F", peace_sign, peace_sign_width, peace_sign_height}, // ✌️ Victory Hand @@ -55,7 +63,9 @@ const Emote emotes[] = { {"\U0001F937", shrug, shrug_width, shrug_height}, // 🤷 Person Shrugging {"\U0001F920", cowboy, cowboy_width, cowboy_height}, // 🤠 Cowboy Hat Face {"\U0001F3A7", deadmau5, deadmau5_width, deadmau5_height}, // 🎧 Headphones +#endif // EMOTE_SET_STANDARD +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_CORE // --- Symbols --- {"\u2714\uFE0F", check_mark, check_mark_width, check_mark_height}, // ✔️ Check Mark {"\u2705", check_mark, check_mark_width, check_mark_height}, // ✅ Check Mark Button @@ -63,7 +73,9 @@ const Emote emotes[] = { {"\U0001F3E0", house, house_width, house_height}, // 🏠 House {"\U0001F5FC", tower, tower_width, tower_height}, // 🗼 Tokyo Tower {"\U0001F4AF", one_hundred, one_hundred_width, one_hundred_height}, // 💯 Hundred Points Symbol +#endif // EMOTE_SET_CORE +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_STANDARD // --- Weather --- {"\u2600", sun, sun_width, sun_height}, // ☀ Sun (without variation selector) {"\u2600\uFE0F", sun, sun_width, sun_height}, // ☀️ Sun (with variation selector) @@ -90,7 +102,9 @@ const Emote emotes[] = { {"\U0001F304", sunrise, sunrise_width, sunrise_height}, // 🌄 Sunrise {"\U0001F306", sunset, sunset_width, sunset_height}, // 🌆 Sunset {"\U0001F307", sunset, sunset_width, sunset_height}, // 🌇 Sunset +#endif // EMOTE_SET_STANDARD +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_FULL // --- Moon Phases --- {"\U0001F311", new_moon, new_moon_width, new_moon_height}, // 🌑 New Moon {"\U0001F312", waxing_crescent_moon, waxing_crescent_moon_width, waxing_crescent_moon_height}, // 🌒 Waxing Crescent Moon @@ -102,13 +116,17 @@ const Emote emotes[] = { {"\U0001F318", waning_crescent_moon, waning_crescent_moon_width, waning_crescent_moon_height}, // 🌘 Waning Crescent Moon {"\U0001F31B", first_quarter_moon_face, first_quarter_moon_face_width, first_quarter_moon_face_height}, // 🌛 First Quarter Moon Face +#endif // EMOTE_SET_FULL +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_STANDARD // --- Misc Faces --- {"\U0001F608", devil, devil_width, devil_height}, // 😈 Smiling Face with Horns {"\U0001F921", clown, clown_width, clown_height}, // 🤡 Clown Face {"\U0001F916", robo, robo_width, robo_height}, // 🤖 Robot Face {"\U0001F479", ogre, ogre_width, ogre_height}, // 👹 Ogre +#endif // EMOTE_SET_STANDARD +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_CORE // --- Hearts (Multiple Unicode Aliases) --- {"\u2665", heart, heart_width, heart_height}, // ♥ Black Heart Suit {"\u2665\uFE0F", heart, heart_width, heart_height}, // ♥️ Black Heart Suit (emoji presentation) @@ -120,7 +138,9 @@ const Emote emotes[] = { {"\U0001F496", heart, heart_width, heart_height}, // 💖 Sparkling Heart {"\U0001F497", heart, heart_width, heart_height}, // 💗 Growing Heart {"\U0001F498", heart, heart_width, heart_height}, // 💘 Heart with Arrow +#endif // EMOTE_SET_CORE +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_FULL // --- Objects --- {"\U0001F4A9", poo, poo_width, poo_height}, // 💩 Pile of Poo {"\U0001F514", bell_icon, bell_icon_width, bell_icon_height}, // 🔔 Bell @@ -138,7 +158,9 @@ const Emote emotes[] = { {"\U0001F37A", beer, beer_width, beer_height}, {"\U0001F954", potato, potato_width, potato_height}, // 🥔 Potato {"\U0001FAB5", wood, wood_width, wood_height}, // 🪵 Wood +#endif // EMOTE_SET_FULL +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_FULL // --- Arrows --- {"\u2193", downwards_arrow, downwards_arrow_width, downwards_arrow_height}, // ↓ Downwards Arrow {"\u2193\uFE0E", downwards_arrow, downwards_arrow_width, downwards_arrow_height}, // ↓︎ Downwards Arrow (text) @@ -172,12 +194,16 @@ const Emote emotes[] = { {"\u2198", south_east_arrow, south_east_arrow_width, south_east_arrow_height}, // ↘ South East Arrow {"\u2198\uFE0E", south_east_arrow, south_east_arrow_width, south_east_arrow_height}, // ↘︎ South East Arrow (text) {"\u2198\uFE0F", south_east_arrow, south_east_arrow_width, south_east_arrow_height}, // ↘️ South East Arrow (emoji) +#endif // EMOTE_SET_FULL +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_FULL // --- Halloween --- {"\U0001F383", jack_o_lantern, jack_o_lantern_width, jack_o_lantern_height}, // 🎃 Jack-O-Lantern {"\U0001F47B", ghost, ghost_width, ghost_height}, // 👻 Ghost {"\U0001F480", skull, skull_width, skull_height}, // 💀 Skull +#endif // EMOTE_SET_FULL +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_FULL // --- Holidays --- {"\U0001F384", christmas_tree, christmas_tree_width, christmas_tree_height}, // 🎄 Christmas Tree {"\U0001F381", wrapped_gift, wrapped_gift_width, wrapped_gift_height}, // 🎁 Wrapped Gift @@ -186,15 +212,23 @@ const Emote emotes[] = { {"\u2721\uFE0F", star_of_david, star_of_david_width, star_of_david_height}, // ✡️ Star of David {"\u26C4", snow_man, snow_man_width, snow_man_height}, // ⛄ Snowman {"\u2603\uFE0F", snow_man, snow_man_width, snow_man_height}, // ☃️ Snowman +#endif // EMOTE_SET_FULL +#if MESHTASTIC_EMOTE_SET >= EMOTE_SET_FULL // --- Misc --- - {"\U0001F4A8", dashing_away, dashing_away_width, dashing_away_height} // 💨 Dashing Away -#endif + {"\U0001F4A8", dashing_away, dashing_away_width, dashing_away_height}, // 💨 Dashing Away +#endif // EMOTE_SET_FULL }; const int numEmotes = sizeof(emotes) / sizeof(emotes[0]); -#ifndef EXCLUDE_EMOJI +#if MESHTASTIC_EMOTE_SET > EMOTE_SET_NONE +// A mis-gated section that empties the table above EMOTE_SET_NONE would not fail to +// build - it would ship a picker with nothing in it - so catch it here instead. +static_assert(sizeof(emotes) / sizeof(emotes[0]) > 0, "emote set is non-empty above EMOTE_SET_NONE"); +#endif + +#if MESHTASTIC_EMOTE_SET > EMOTE_SET_NONE const unsigned char thumbup[] PROGMEM = {0x00, 0x03, 0x80, 0x04, 0x80, 0x04, 0x40, 0x04, 0x20, 0x02, 0x18, 0x02, 0x06, 0x3F, 0x06, 0x40, 0x06, 0x70, 0x06, 0x40, 0x06, 0x70, 0x06, 0x40, 0x06, 0x30, 0x08, 0x20, 0xF0, 0x1F, 0x00, 0x00}; diff --git a/src/graphics/emotes.h b/src/graphics/emotes.h index 9646ac78ef0..6eab6fcd628 100644 --- a/src/graphics/emotes.h +++ b/src/graphics/emotes.h @@ -1,6 +1,41 @@ #pragma once +#include "configuration.h" +#include "memory/FlashClass.h" #include +// === Emote set ladder === +// The emote table is pure flash: 16x16 XBM bitmaps in PROGMEM plus a 146-entry +// index. It costs no RAM, so it tiers off MESHTASTIC_FLASH_CLASS (memory/FlashClass.h) +// rather than the RAM ladder in memory/MemClass.h. +// +// EMOTE_SET_NONE no bitmaps; emoji render as their text label +// EMOTE_SET_CORE acknowledgement, alerts, mesh status, heart +// EMOTE_SET_STANDARD + faces, gestures and weather +// EMOTE_SET_FULL + moon phases, objects, arrows, seasonal +// +// Compare ordinally (>=). Each section of the table in emotes.cpp carries its own +// tier gate, so picker order is unchanged as tiers drop out. Dropping entries leaves +// their bitmaps unreferenced and -fdata-sections/--gc-sections discards them, so the +// saving is the index plus the bitmap data plus (at NONE, under LTO) the picker itself. +#define EMOTE_SET_NONE 0 +#define EMOTE_SET_CORE 1 +#define EMOTE_SET_STANDARD 2 +#define EMOTE_SET_FULL 3 + +#ifndef MESHTASTIC_EMOTE_SET +#ifdef EXCLUDE_EMOJI // long-standing spelling of "no emotes at all" +#define MESHTASTIC_EMOTE_SET EMOTE_SET_NONE +#elif MESHTASTIC_FLASH_CLASS <= FLASH_CLASS_TINY +#define MESHTASTIC_EMOTE_SET EMOTE_SET_NONE +#elif MESHTASTIC_FLASH_CLASS == FLASH_CLASS_SMALL +// nRF52840 is the tightest screen-capable region we ship - rak4631 sits at 97% of it +// on develop - so this class trades the seasonal/decorative tail for headroom. +#define MESHTASTIC_EMOTE_SET EMOTE_SET_STANDARD +#else +#define MESHTASTIC_EMOTE_SET EMOTE_SET_FULL +#endif +#endif // MESHTASTIC_EMOTE_SET + namespace graphics { @@ -15,7 +50,7 @@ struct Emote { extern const Emote emotes[/* numEmotes */]; extern const int numEmotes; -#ifndef EXCLUDE_EMOJI +#if MESHTASTIC_EMOTE_SET > EMOTE_SET_NONE // === Emote Bitmaps === #define thumbs_height 16 #define thumbs_width 16 @@ -425,6 +460,6 @@ extern const unsigned char wood[] PROGMEM; #define beer_width 16 #define beer_height 16 extern const unsigned char beer[] PROGMEM; -#endif // EXCLUDE_EMOJI +#endif // MESHTASTIC_EMOTE_SET > EMOTE_SET_NONE } // namespace graphics diff --git a/src/memory/FlashClass.h b/src/memory/FlashClass.h new file mode 100644 index 00000000000..b1a3c33bf20 --- /dev/null +++ b/src/memory/FlashClass.h @@ -0,0 +1,46 @@ +#pragma once + +// Central flash-class ladder: flash-sized tables key their per-platform tier off +// MESHTASTIC_FLASH_CLASS. Classes rank the *app flash region* a target actually has +// to spend - not raw part size, and deliberately not RAM. +// +// FLASH_CLASS_TINY <256 KB app region STM32WL +// FLASH_CLASS_SMALL ~784 KB nRF52840 (0x26000..0xEA000, warm store reserved) +// FLASH_CLASS_MEDIUM ~1.9-3 MB app part. classic ESP32 / S2 / C3, RP2040/RP2350 +// FLASH_CLASS_LARGE 4 MB+ app, or host ESP32-S3 / C6 / P4, portduino +// +// This is the sibling of memory/MemClass.h, and the two ladders disagree on purpose. +// MemClass ranks usable app heap; a chip can be poor in one resource and rich in the +// other. Classic ESP32 and nRF52840 are both MEM_CLASS_SMALL, but the ESP32 has well +// over twice the app flash, so a flash-shaped decision keyed off MESHTASTIC_MEM_CLASS +// would trim the wrong targets. The reverse trap is just as real within a single class: +// rak4631 and nrf52_promicro_diy_tcxo are the same chip and the same FLASH_CLASS_SMALL, +// yet one ships with ~22 KB of headroom and the other does not fit at all - so a class +// is a *default*, never a verdict. Tight variants predefine their own value. +// +// Compare ordinally (>=). An unclassified chip lands in SMALL on purpose: a smaller +// table is a recoverable default, an image that overruns its region is not. Consumer +// ladders stay #ifndef-guarded so a variant can always override. Requires the ARCH_* +// macros, so include after (or via) configuration.h. + +#define FLASH_CLASS_TINY 1 +#define FLASH_CLASS_SMALL 2 +#define FLASH_CLASS_MEDIUM 3 +#define FLASH_CLASS_LARGE 4 + +#ifndef MESHTASTIC_FLASH_CLASS +#if defined(ARCH_STM32WL) +#define MESHTASTIC_FLASH_CLASS FLASH_CLASS_TINY +#elif defined(ARCH_NRF52) || defined(ARCH_NRF54L15) +#define MESHTASTIC_FLASH_CLASS FLASH_CLASS_SMALL +#elif defined(ARCH_PORTDUINO) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6) || \ + defined(CONFIG_IDF_TARGET_ESP32P4) +// S3/C6/P4 boards overwhelmingly ship 8-16 MB. The 4 MB-part S3 variants that run +// close to their app partition predefine MESHTASTIC_FLASH_CLASS instead. +#define MESHTASTIC_FLASH_CLASS FLASH_CLASS_LARGE +#elif defined(ARCH_ESP32) || defined(ARCH_RP2040) +#define MESHTASTIC_FLASH_CLASS FLASH_CLASS_MEDIUM +#else +#define MESHTASTIC_FLASH_CLASS FLASH_CLASS_SMALL +#endif +#endif // MESHTASTIC_FLASH_CLASS diff --git a/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini b/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini index c4cff6b13fa..9805af6f3c7 100644 --- a/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini +++ b/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini @@ -15,7 +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 + -D MESHTASTIC_EMOTE_SET=EMOTE_SET_NONE ; this variant builds 4 radio driver families and is the largest nrf52 image; even the CORE emote set doesn'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