refactor(prefs): centralise home-page bit numbering in NodePrefs::HomePageBit

pageBit/bitToPage in HomeScreen and homePageBitIndex in SettingsScreen
each spelled out the bit assignment with magic numbers 0..10. Lift the
numbering into a NodePrefs::HomePageBit enum (HPB_CLOCK … HPB_QUICK_MSG,
HPB_COUNT) and route every reference through it: mapping functions, the
HP_* bitmasks, the homePageLabel table sizing, loop bounds over
page_order, the bounds check on page_order[0], the "always-visible"
discriminator for SETTINGS/QUICK_MSG.

Per-class enums (HomeScreen::HomePage, SettingsScreen::SettingItem)
stay — they index different concerns (navigation page vs. settings
row). The mapping functions still exist, but now reference a single
source of truth for the bit values.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-05-24 22:26:56 +02:00
co-authored by Claude Sonnet 4.6
parent 900f2d59e9
commit a4b4362b1b
4 changed files with 86 additions and 67 deletions
+1 -1
View File
@@ -300,7 +300,7 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
// Migration: pre-magic firmware wrote page_order without a flag. If we see a plausible // Migration: pre-magic firmware wrote page_order without a flag. If we see a plausible
// first entry from such a save, accept it once — savePrefs will then persist the magic. // first entry from such a save, accept it once — savePrefs will then persist the magic.
if (_prefs.page_order_set != NodePrefs::PAGE_ORDER_MAGIC if (_prefs.page_order_set != NodePrefs::PAGE_ORDER_MAGIC
&& _prefs.page_order[0] >= 1 && _prefs.page_order[0] <= 11) { && _prefs.page_order[0] >= 1 && _prefs.page_order[0] <= NodePrefs::HPB_COUNT) {
_prefs.page_order_set = NodePrefs::PAGE_ORDER_MAGIC; _prefs.page_order_set = NodePrefs::PAGE_ORDER_MAGIC;
} }
+37 -15
View File
@@ -81,9 +81,11 @@ struct NodePrefs { // persisted to file
DmMelodyEntry dm_melody[DM_MELODY_TABLE_MAX]; DmMelodyEntry dm_melody[DM_MELODY_TABLE_MAX];
uint8_t use_lemon_font; // 0=default Adafruit font, 1=Lemon font (Unicode, pixel-accurate wrap) uint8_t use_lemon_font; // 0=default Adafruit font, 1=Lemon font (Unicode, pixel-accurate wrap)
uint8_t display_rotation; // 0-3; only used on e-ink displays uint8_t display_rotation; // 0-3; only used on e-ink displays
// Home screen page order: each byte = bit-index+1 (see HP_* bit positions + 9=Settings, 10=Messages). // Home screen page order: each byte = HomePageBit + 1. 0 terminates the list.
// 0 = end of list. Validity gated by page_order_set magic (see below) — not by entry value range, // Validity gated by page_order_set magic (see below) — not by entry value range,
// so a junk byte in 1..11 cannot trigger custom-order mode. // so a junk byte in 1..HPB_COUNT cannot trigger custom-order mode.
// (Array length = HPB_COUNT, declared as literal so the field offset is stable
// across builds that add new HomePageBit entries.)
uint8_t page_order[11]; uint8_t page_order[11];
uint8_t joystick_rotation; // 0-3 steps CW; independent of display_rotation uint8_t joystick_rotation; // 0-3 steps CW; independent of display_rotation
uint8_t eink_full_refresh_every; // index into {0,5,10,20,30}: full refresh every N partials (0=off) uint8_t eink_full_refresh_every; // index into {0,5,10,20,30}: full refresh every N partials (0=off)
@@ -96,25 +98,45 @@ struct NodePrefs { // persisted to file
// High 24 bits identify the file format; low byte is the schema revision. // High 24 bits identify the file format; low byte is the schema revision.
static const uint32_t SCHEMA_SENTINEL = 0xC0DE0001; static const uint32_t SCHEMA_SENTINEL = 0xC0DE0001;
// Bit-index for each home page. Used by page_order (entries store bit+1) and
// by home_pages_mask. Single source of truth — both HomeScreen::pageBit/bitToPage
// and SettingsScreen::homePageBitIndex route their per-enum lookups through these.
enum HomePageBit : uint8_t {
HPB_CLOCK = 0,
HPB_RECENT = 1,
HPB_RADIO = 2,
HPB_BLUETOOTH = 3,
HPB_ADVERT = 4,
HPB_GPS = 5,
HPB_SENSORS = 6,
HPB_TOOLS = 7,
HPB_SHUTDOWN = 8,
HPB_SETTINGS = 9,
HPB_QUICK_MSG = 10,
HPB_COUNT = 11,
};
// Bitmasks for home_pages_mask (bit=1 → page visible; 0 field = all visible). // Bitmasks for home_pages_mask (bit=1 → page visible; 0 field = all visible).
static const uint16_t HP_CLOCK = 1 << 0; // SETTINGS and QUICK_MSG have no mask bit — they're always visible.
static const uint16_t HP_RECENT = 1 << 1; static const uint16_t HP_CLOCK = 1 << HPB_CLOCK;
static const uint16_t HP_RADIO = 1 << 2; static const uint16_t HP_RECENT = 1 << HPB_RECENT;
static const uint16_t HP_BLUETOOTH = 1 << 3; static const uint16_t HP_RADIO = 1 << HPB_RADIO;
static const uint16_t HP_ADVERT = 1 << 4; static const uint16_t HP_BLUETOOTH = 1 << HPB_BLUETOOTH;
static const uint16_t HP_GPS = 1 << 5; static const uint16_t HP_ADVERT = 1 << HPB_ADVERT;
static const uint16_t HP_SENSORS = 1 << 6; static const uint16_t HP_GPS = 1 << HPB_GPS;
static const uint16_t HP_TOOLS = 1 << 7; static const uint16_t HP_SENSORS = 1 << HPB_SENSORS;
static const uint16_t HP_SHUTDOWN = 1 << 8; static const uint16_t HP_TOOLS = 1 << HPB_TOOLS;
static const uint16_t HP_SHUTDOWN = 1 << HPB_SHUTDOWN;
static const uint16_t HP_ALL = 0x01FF; static const uint16_t HP_ALL = 0x01FF;
// Label for home page by bit-index (010); returns "" for out-of-range. // Label for home page by bit-index; returns "" for out-of-range.
// Array indices match HomePageBit values.
static const char* homePageLabel(uint8_t bit) { static const char* homePageLabel(uint8_t bit) {
static const char* labels[] = { static const char* labels[HPB_COUNT] = {
"Clock", "Recent", "Radio", "Bluetooth", "Advert", "Clock", "Recent", "Radio", "Bluetooth", "Advert",
"GPS", "Sensors", "Tools", "Shutdown", "Settings", "Messages" "GPS", "Sensors", "Tools", "Shutdown", "Settings", "Messages"
}; };
return (bit < 11) ? labels[bit] : ""; return (bit < HPB_COUNT) ? labels[bit] : "";
} }
static void buildRTTTLString(const uint8_t* notes, uint8_t len, uint8_t bpm_idx, static void buildRTTTLString(const uint8_t* notes, uint8_t len, uint8_t bpm_idx,
@@ -178,12 +178,14 @@ class SettingsScreen : public UIScreen {
uint16_t homePageBit(int item) const { uint16_t homePageBit(int item) const {
int bit = homePageBitIndex(item); int bit = homePageBitIndex(item);
return (bit >= 0 && bit < 9) ? (uint16_t)(1 << bit) : 0; // Bits 0..HPB_SHUTDOWN have mask bits in home_pages_mask; SETTINGS and
// QUICK_MSG are always visible (no mask bit) and return 0.
return (bit >= 0 && bit < NodePrefs::HPB_SETTINGS) ? (uint16_t)(1 << bit) : 0;
} }
const char* homePageLabel(int item) const { const char* homePageLabel(int item) const {
int bit = homePageBitIndex(item); int bit = homePageBitIndex(item);
return NodePrefs::homePageLabel((uint8_t)(bit >= 0 ? bit : 11)); return NodePrefs::homePageLabel((uint8_t)(bit >= 0 ? bit : NodePrefs::HPB_COUNT));
} }
bool homePageVisible(int item, const NodePrefs* p) const { bool homePageVisible(int item, const NodePrefs* p) const {
@@ -198,23 +200,24 @@ class SettingsScreen : public UIScreen {
return item != HOME_SETTINGS && item != HOME_QUICK_MSG; return item != HOME_SETTINGS && item != HOME_QUICK_MSG;
} }
// Returns the bit-index (0-10) used in page_order for this SettingItem, or -1. // Returns the bit-index used in page_order for this SettingItem, or -1.
// Bit-index values are defined once in NodePrefs::HomePageBit.
int homePageBitIndex(int item) const { int homePageBitIndex(int item) const {
if (item == HOME_CLOCK) return 0; if (item == HOME_CLOCK) return NodePrefs::HPB_CLOCK;
if (item == HOME_RECENT) return 1; if (item == HOME_RECENT) return NodePrefs::HPB_RECENT;
if (item == HOME_RADIO) return 2; if (item == HOME_RADIO) return NodePrefs::HPB_RADIO;
if (item == HOME_BT) return 3; if (item == HOME_BT) return NodePrefs::HPB_BLUETOOTH;
if (item == HOME_ADVERT) return 4; if (item == HOME_ADVERT) return NodePrefs::HPB_ADVERT;
#if ENV_INCLUDE_GPS == 1 #if ENV_INCLUDE_GPS == 1
if (item == HOME_GPS) return 5; if (item == HOME_GPS) return NodePrefs::HPB_GPS;
#endif #endif
#if UI_SENSORS_PAGE == 1 #if UI_SENSORS_PAGE == 1
if (item == HOME_SENSORS) return 6; if (item == HOME_SENSORS) return NodePrefs::HPB_SENSORS;
#endif #endif
if (item == HOME_TOOLS) return 7; if (item == HOME_TOOLS) return NodePrefs::HPB_TOOLS;
if (item == HOME_SHUTDOWN) return 8; if (item == HOME_SHUTDOWN) return NodePrefs::HPB_SHUTDOWN;
if (item == HOME_SETTINGS) return 9; if (item == HOME_SETTINGS) return NodePrefs::HPB_SETTINGS;
if (item == HOME_QUICK_MSG) return 10; if (item == HOME_QUICK_MSG) return NodePrefs::HPB_QUICK_MSG;
return -1; return -1;
} }
@@ -223,9 +226,9 @@ class SettingsScreen : public UIScreen {
if (!p || p->page_order_set != NodePrefs::PAGE_ORDER_MAGIC) return 0; if (!p || p->page_order_set != NodePrefs::PAGE_ORDER_MAGIC) return 0;
int bit = homePageBitIndex(item); int bit = homePageBitIndex(item);
if (bit < 0) return 0; if (bit < 0) return 0;
for (int i = 0; i < 11; i++) { for (int i = 0; i < NodePrefs::HPB_COUNT; i++) {
uint8_t v = p->page_order[i]; uint8_t v = p->page_order[i];
if (v < 1 || v > 11) break; if (v < 1 || v > NodePrefs::HPB_COUNT) break;
if ((int)(v - 1) == bit) return i + 1; if ((int)(v - 1) == bit) return i + 1;
} }
return 0; return 0;
@@ -237,9 +240,9 @@ class SettingsScreen : public UIScreen {
if (!p) return; if (!p) return;
if (p->page_order_set == NodePrefs::PAGE_ORDER_MAGIC) { if (p->page_order_set == NodePrefs::PAGE_ORDER_MAGIC) {
// Order was previously set — verify CLOCK is present to guard against partial/corrupted data. // Order was previously set — verify CLOCK is present to guard against partial/corrupted data.
for (int i = 0; i < 11; i++) { for (int i = 0; i < NodePrefs::HPB_COUNT; i++) {
uint8_t v = p->page_order[i]; uint8_t v = p->page_order[i];
if (v < 1 || v > 11) break; if (v < 1 || v > NodePrefs::HPB_COUNT) break;
if (v == 0 + 1) return; // CLOCK found, order is intact if (v == 0 + 1) return; // CLOCK found, order is intact
} }
// CLOCK missing — reset and fall through to full re-init. // CLOCK missing — reset and fall through to full re-init.
@@ -262,7 +265,7 @@ class SettingsScreen : public UIScreen {
p->page_order[j++] = 7 + 1; // TOOLS p->page_order[j++] = 7 + 1; // TOOLS
p->page_order[j++] = 10 + 1; // MESSAGES (QUICK_MSG) p->page_order[j++] = 10 + 1; // MESSAGES (QUICK_MSG)
p->page_order[j++] = 8 + 1; // SHUTDOWN p->page_order[j++] = 8 + 1; // SHUTDOWN
while (j < 11) p->page_order[j++] = 0; while (j < NodePrefs::HPB_COUNT) p->page_order[j++] = 0;
p->page_order_set = NodePrefs::PAGE_ORDER_MAGIC; p->page_order_set = NodePrefs::PAGE_ORDER_MAGIC;
} }
@@ -272,9 +275,9 @@ class SettingsScreen : public UIScreen {
int bit = homePageBitIndex(item); int bit = homePageBitIndex(item);
if (bit < 0) return; if (bit < 0) return;
int cur = -1, total = 0; int cur = -1, total = 0;
for (int i = 0; i < 11; i++) { for (int i = 0; i < NodePrefs::HPB_COUNT; i++) {
uint8_t v = p->page_order[i]; uint8_t v = p->page_order[i];
if (v < 1 || v > 11) break; if (v < 1 || v > NodePrefs::HPB_COUNT) break;
if ((int)(v - 1) == bit) cur = i; if ((int)(v - 1) == bit) cur = i;
total++; total++;
} }
+24 -30
View File
@@ -148,47 +148,41 @@ class HomeScreen : public UIScreen {
AdvertPath recent[UI_RECENT_LIST_SIZE]; AdvertPath recent[UI_RECENT_LIST_SIZE];
int pageBit(int page) const { int pageBit(int page) const {
if (page == CLOCK) return 0; if (page == CLOCK) return NodePrefs::HPB_CLOCK;
if (page == RECENT) return 1; if (page == RECENT) return NodePrefs::HPB_RECENT;
if (page == RADIO) return 2; if (page == RADIO) return NodePrefs::HPB_RADIO;
if (page == BLUETOOTH) return 3; if (page == BLUETOOTH) return NodePrefs::HPB_BLUETOOTH;
if (page == ADVERT) return 4; if (page == ADVERT) return NodePrefs::HPB_ADVERT;
#if ENV_INCLUDE_GPS == 1 #if ENV_INCLUDE_GPS == 1
if (page == GPS) return 5; if (page == GPS) return NodePrefs::HPB_GPS;
#endif #endif
#if UI_SENSORS_PAGE == 1 #if UI_SENSORS_PAGE == 1
if (page == SENSORS) return 6; if (page == SENSORS) return NodePrefs::HPB_SENSORS;
#endif #endif
if (page == TOOLS) return 7; if (page == TOOLS) return NodePrefs::HPB_TOOLS;
if (page == SHUTDOWN) return 8; if (page == SHUTDOWN) return NodePrefs::HPB_SHUTDOWN;
return -1; // SETTINGS, QUICK_MSG always visible return -1; // SETTINGS, QUICK_MSG always visible (no mask bit)
} }
// Maps page_order bit-index (0-10) back to the HomePage enum value for this build. // Maps page_order bit-index back to the HomePage enum value for this build.
// Returns -1 if the page is not compiled in. // Returns -1 if the page is not compiled in.
int bitToPage(int bit) const { int bitToPage(int bit) const {
switch (bit) { switch (bit) {
case 0: return CLOCK; case NodePrefs::HPB_CLOCK: return CLOCK;
case 1: return RECENT; case NodePrefs::HPB_RECENT: return RECENT;
case 2: return RADIO; case NodePrefs::HPB_RADIO: return RADIO;
case 3: return BLUETOOTH; case NodePrefs::HPB_BLUETOOTH: return BLUETOOTH;
case 4: return ADVERT; case NodePrefs::HPB_ADVERT: return ADVERT;
case 5:
#if ENV_INCLUDE_GPS == 1 #if ENV_INCLUDE_GPS == 1
return GPS; case NodePrefs::HPB_GPS: return GPS;
#else
return -1;
#endif #endif
case 6:
#if UI_SENSORS_PAGE == 1 #if UI_SENSORS_PAGE == 1
return SENSORS; case NodePrefs::HPB_SENSORS: return SENSORS;
#else
return -1;
#endif #endif
case 7: return TOOLS; case NodePrefs::HPB_TOOLS: return TOOLS;
case 8: return SHUTDOWN; case NodePrefs::HPB_SHUTDOWN: return SHUTDOWN;
case 9: return SETTINGS; case NodePrefs::HPB_SETTINGS: return SETTINGS;
case 10: return QUICK_MSG; case NodePrefs::HPB_QUICK_MSG: return QUICK_MSG;
default: return -1; default: return -1;
} }
} }
@@ -206,9 +200,9 @@ class HomeScreen : public UIScreen {
int n = 0; int n = 0;
bool custom = _node_prefs && _node_prefs->page_order_set == NodePrefs::PAGE_ORDER_MAGIC; bool custom = _node_prefs && _node_prefs->page_order_set == NodePrefs::PAGE_ORDER_MAGIC;
if (custom) { if (custom) {
for (int i = 0; i < 11; i++) { for (int i = 0; i < NodePrefs::HPB_COUNT; i++) {
uint8_t v = _node_prefs->page_order[i]; uint8_t v = _node_prefs->page_order[i];
if (v < 1 || v > 11) break; if (v < 1 || v > NodePrefs::HPB_COUNT) break;
int pg = bitToPage(v - 1); int pg = bitToPage(v - 1);
if (pg >= 0 && pg < (int)Count && isPageVisible(pg)) out[n++] = pg; if (pg >= 0 && pg < (int)Count && isPageVisible(pg)) out[n++] = pg;
} }