From 7add9019ee6392ca95da9482f124c018253a834c Mon Sep 17 00:00:00 2001 From: mikecarper Date: Sat, 26 Sep 2026 01:38:40 -0700 Subject: [PATCH] Give dual-profile companion screens manual R2 pages --- examples/companion_radio/ui-new/UITask.cpp | 87 ++++++++++++++------- examples/companion_radio/ui-orig/UITask.cpp | 41 +++++++--- examples/companion_radio/ui-orig/UITask.h | 2 +- examples/companion_radio/ui-tiny/UITask.cpp | 69 ++++++++++------ 4 files changed, 134 insertions(+), 65 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index beddaf9d..ec8776f5 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -420,6 +420,9 @@ class HomeScreen : public UIScreen { #endif RECENT, RADIO, + // Only visible when the secondary radio profile is configured. + RADIO2, + RADIO_STATUS, #ifdef COMPANION_EXCLUSIVE_WIFI_BLE TRANSPORT, #else @@ -457,6 +460,7 @@ class HomeScreen : public UIScreen { uint32_t _uptime_last_millis; uint64_t _uptime_millis; uint32_t _radio_profile_page_started_at = 0; + uint8_t _radio_status_page = 0; bool _dual_radio_enabled_seen = false; AdvertPath recent[UI_RECENT_LIST_SIZE]; #if !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0)) @@ -597,23 +601,22 @@ class HomeScreen : public UIScreen { void resetRadioProfileDisplayPage() { _radio_profile_page_started_at = millis(); + _radio_status_page = 0; _dual_radio_enabled_seen = the_mesh.isDualRadioActive(); } - bool showingSecondaryRadioProfilePage(DisplayDriver& display, - int status_top) { - const bool dual_radio_enabled = the_mesh.isDualRadioActive(); - const uint32_t now = millis(); - if (dual_radio_enabled != _dual_radio_enabled_seen) { - _dual_radio_enabled_seen = dual_radio_enabled; - _radio_profile_page_started_at = now; + bool isPageVisible(uint8_t page) const { + return the_mesh.isDualRadioActive() + || (page != HomePage::RADIO2 && page != HomePage::RADIO_STATUS); + } + + void movePage(int direction) { + do { + _page = (_page + HomePage::Count + direction) % HomePage::Count; + } while (!isPageVisible(_page)); + if (_page == HomePage::RADIO || _page == HomePage::RADIO_STATUS) { + resetRadioProfileDisplayPage(); } - display.setTextSize(1); - const uint8_t status_pages = mesh::ui::radioProfileSystemStatusPageCount( - display, dual_radio_enabled, status_top); - return mesh::ui::showSecondaryRadioProfilePage(dual_radio_enabled, - status_pages, - now - _radio_profile_page_started_at); } int radioProfileRefreshMillis() const { @@ -642,7 +645,9 @@ public: void showFirstPage() { _page = HomePage::FIRST; } #if COMPANION_FEATURE_READER - bool isRadioPage() const { return _page == HomePage::RADIO; } + bool isRadioPage() const { + return _page == HomePage::RADIO || _page == HomePage::RADIO2; + } #endif bool isTransportSelectorPage() const { @@ -658,6 +663,13 @@ public: #endif void poll() override { + if (_dual_radio_enabled_seen != the_mesh.isDualRadioActive()) { + resetRadioProfileDisplayPage(); + } + if (!isPageVisible(_page)) { + _page = HomePage::RADIO; + resetRadioProfileDisplayPage(); + } #if UI_WIFI_SETUP_HOME_PAGE == 1 const bool wifi_setup_active = WebConfigServer::getSetupInfo( nullptr, 0, nullptr, 0); @@ -715,13 +727,17 @@ public: display.setColor(UIColor::corp_blue); } int y = header_height + 2; - int x = display.width() / 2 - 5 * (HomePage::Count-1); - for (uint8_t i = 0; i < HomePage::Count; i++, x += 10) { + const int visible_pages = HomePage::Count + - (the_mesh.isDualRadioActive() ? 0 : 2); + int x = display.width() / 2 - 5 * (visible_pages - 1); + for (uint8_t i = 0; i < HomePage::Count; i++) { + if (!isPageVisible(i)) continue; if (i == _page) { display.fillRect(x-1, y-1, 4, 4); } else { display.fillRect(x, y, 2, 2); } + x += 10; } if (_page == HomePage::FIRST) { @@ -956,7 +972,8 @@ public: display.setCursor(display.width() - timestamp_width - 1, y); display.print(tmp); } - } else if (_page == HomePage::RADIO) { + } else if (_page == HomePage::RADIO || _page == HomePage::RADIO2 + || _page == HomePage::RADIO_STATUS) { display.setColor(UIColor::primary_txt); display.setTextSize(1); const auto* radio = the_mesh.getProfileRadio(); @@ -965,14 +982,22 @@ public: const uint8_t status_pages = mesh::ui::radioProfileSystemStatusPageCount( display, dual_radio, body_top); uint8_t status_page_index = 0; - if (mesh::ui::showRadioProfileSystemStatusPage(dual_radio, status_pages, - millis() - _radio_profile_page_started_at, &status_page_index)) { + const bool status_page = dual_radio + ? _page == HomePage::RADIO_STATUS + : mesh::ui::showRadioProfileSystemStatusPage( + false, status_pages, + millis() - _radio_profile_page_started_at, + &status_page_index); + if (status_page) { + if (dual_radio && status_pages != 0) { + status_page_index = _radio_status_page % status_pages; + } mesh::ui::drawRadioProfileSystemStatusPage(display, radioProfileSystemStatus(*_node_prefs), status_page_index, body_top); - return radioProfileRefreshMillis(); + return dual_radio ? UI_RADIO_REFRESH_MILLIS + : radioProfileRefreshMillis(); } - const bool secondary_page = showingSecondaryRadioProfilePage(display, - body_top); + const bool secondary_page = dual_radio && _page == HomePage::RADIO2; float freq = _node_prefs->freq; float bw = _node_prefs->bw; uint8_t sf = _node_prefs->sf; @@ -1267,7 +1292,11 @@ public: } #endif } - if (_page == HomePage::RADIO) return radioProfileRefreshMillis(); + if (_page == HomePage::RADIO && !the_mesh.isDualRadioActive()) { + return radioProfileRefreshMillis(); + } + if (_page == HomePage::RADIO || _page == HomePage::RADIO2 + || _page == HomePage::RADIO_STATUS) return UI_RADIO_REFRESH_MILLIS; #if UI_MESSAGES_HOME_PAGE == 1 if (_page == HomePage::MESSAGES) return 1000; #endif @@ -1281,19 +1310,17 @@ public: // Navigation codes exceed 0x7f; keep them valid with signed char too. const uint8_t key = static_cast(c); if (key == KEY_LEFT || key == KEY_PREV) { - _page = (_page + HomePage::Count - 1) % HomePage::Count; - if (_page == HomePage::RADIO) resetRadioProfileDisplayPage(); + movePage(-1); return true; } #if COMPANION_FEATURE_READER - if (key == KEY_ENTER && _page == HomePage::RADIO) { + if (key == KEY_ENTER && isRadioPage()) { _task->showReader(); return true; } #endif if (key == KEY_NEXT || key == KEY_RIGHT) { - _page = (_page + 1) % HomePage::Count; - if (_page == HomePage::RADIO) resetRadioProfileDisplayPage(); + movePage(1); if (_page == HomePage::RECENT) { _task->showAlert("Recent adverts", 800); } @@ -1304,6 +1331,10 @@ public: #endif return true; } + if (key == KEY_ENTER && _page == HomePage::RADIO_STATUS) { + _radio_status_page++; + return true; + } #ifdef COMPANION_EXCLUSIVE_WIFI_BLE if (_page == HomePage::TRANSPORT && (key == KEY_ENTER || key == KEY_UP || key == KEY_DOWN)) { diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index c47f6920..b44c38df 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -162,32 +162,36 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, CompanionNode void UITask::resetRadioProfileDisplayPage() { _radio_profile_page_started_at = millis(); _dual_radio_enabled_seen = the_mesh.isDualRadioActive(); - _radio_profile_display_page_seen = 0; + _radio_profile_display_page = 0; } bool UITask::showingSecondaryRadioProfilePage() { const bool dual_radio_enabled = the_mesh.isDualRadioActive(); - const uint32_t now = millis(); - if (dual_radio_enabled != _dual_radio_enabled_seen) { - _dual_radio_enabled_seen = dual_radio_enabled; - _radio_profile_page_started_at = now; + if (dual_radio_enabled) { + return mesh::ui::showManualSecondaryRadioProfilePage( + true, _radio_profile_display_page); } const uint8_t status_pages = radioProfileStatusPageCount(*_display, dual_radio_enabled); return mesh::ui::showSecondaryRadioProfilePage(dual_radio_enabled, status_pages, - now - _radio_profile_page_started_at); + millis() - _radio_profile_page_started_at); } void UITask::serviceRadioProfileDisplayPage() { const bool dual_radio_enabled = the_mesh.isDualRadioActive(); + if (dual_radio_enabled != _dual_radio_enabled_seen) { + resetRadioProfileDisplayPage(); + _need_refresh = true; + } + if (dual_radio_enabled) return; // Button presses own all dual-radio pages. const uint8_t status_pages = radioProfileStatusPageCount(*_display, dual_radio_enabled); const uint8_t page = mesh::ui::radioProfileDisplayPageIndex( dual_radio_enabled, status_pages, millis() - _radio_profile_page_started_at); - if (page != _radio_profile_display_page_seen) { - _radio_profile_display_page_seen = page; + if (page != _radio_profile_display_page) { + _radio_profile_display_page = page; _need_refresh = true; } } @@ -356,9 +360,14 @@ void UITask::renderCurrScreen() { const uint8_t status_pages = radioProfileStatusPageCount( *_display, dual_radio_enabled); uint8_t status_page_index = 0; - if (mesh::ui::showRadioProfileSystemStatusPage(dual_radio_enabled, - status_pages, millis() - _radio_profile_page_started_at, - &status_page_index)) { + const bool status_page = dual_radio_enabled + ? mesh::ui::showManualRadioProfileSystemStatusPage( + true, status_pages, _radio_profile_display_page, + &status_page_index) + : mesh::ui::showRadioProfileSystemStatusPage( + false, status_pages, millis() - _radio_profile_page_started_at, + &status_page_index); + if (status_page) { mesh::ui::drawRadioProfileSystemStatusPage(*_display, radioProfileSystemStatus(*_node_prefs, *_board), status_page_index); _need_refresh = false; @@ -696,7 +705,15 @@ void UITask::handleButtonShortPress() { if (_origin[0] && _msg[0]) { clearMsgPreview(); } else { - // Otherwise, refresh the display + if (!_alert[0] && !isPairingScreenActive() + && the_mesh.isDualRadioActive()) { + const uint8_t status_pages = radioProfileStatusPageCount( + *_display, true); + const uint8_t page_count = mesh::ui::radioProfileDisplayPageCount( + true, status_pages); + _radio_profile_display_page = + (_radio_profile_display_page + 1) % page_count; + } _need_refresh = true; } } else { diff --git a/examples/companion_radio/ui-orig/UITask.h b/examples/companion_radio/ui-orig/UITask.h index 7d253679..09b60dcb 100644 --- a/examples/companion_radio/ui-orig/UITask.h +++ b/examples/companion_radio/ui-orig/UITask.h @@ -44,7 +44,7 @@ class UITask : public AbstractUITask { unsigned long ui_started_at; uint32_t _radio_profile_page_started_at = 0; bool _dual_radio_enabled_seen = false; - uint8_t _radio_profile_display_page_seen = 0; + uint8_t _radio_profile_display_page = 0; // Button handlers #ifdef PIN_USER_BTN diff --git a/examples/companion_radio/ui-tiny/UITask.cpp b/examples/companion_radio/ui-tiny/UITask.cpp index fa8e2b44..a98bfe66 100644 --- a/examples/companion_radio/ui-tiny/UITask.cpp +++ b/examples/companion_radio/ui-tiny/UITask.cpp @@ -138,6 +138,9 @@ class HomeScreen : public UIScreen { FIRST, RECENT, RADIO, + // Only visible when the secondary radio profile is configured. + RADIO2, + RADIO_STATUS, BLUETOOTH, ADVERT, #if ENV_INCLUDE_GPS == 1 @@ -164,6 +167,7 @@ class HomeScreen : public UIScreen { int sensors_scroll_offset = 0; int next_sensors_refresh = 0; uint32_t _radio_profile_page_started_at = 0; + uint8_t _radio_status_page = 0; bool _dual_radio_enabled_seen = false; void refresh_sensors() { @@ -189,22 +193,22 @@ class HomeScreen : public UIScreen { void resetRadioProfileDisplayPage() { _radio_profile_page_started_at = millis(); + _radio_status_page = 0; _dual_radio_enabled_seen = the_mesh.isDualRadioActive(); } - bool showingSecondaryRadioProfilePage(DisplayDriver& display) { - const bool dual_radio_enabled = the_mesh.isDualRadioActive(); - const uint32_t now = millis(); - if (dual_radio_enabled != _dual_radio_enabled_seen) { - _dual_radio_enabled_seen = dual_radio_enabled; - _radio_profile_page_started_at = now; + bool isPageVisible(uint8_t page) const { + return the_mesh.isDualRadioActive() + || (page != HomePage::RADIO2 && page != HomePage::RADIO_STATUS); + } + + void movePage(int direction) { + do { + _page = (_page + HomePage::Count + direction) % HomePage::Count; + } while (!isPageVisible(_page)); + if (_page == HomePage::RADIO || _page == HomePage::RADIO_STATUS) { + resetRadioProfileDisplayPage(); } - display.setTextSize(1); - const uint8_t status_pages = mesh::ui::radioProfileSystemStatusPageCount( - display, dual_radio_enabled, 8); - return mesh::ui::showSecondaryRadioProfilePage(dual_radio_enabled, - status_pages, - now - _radio_profile_page_started_at); } int radioProfileRefreshMillis() const { @@ -224,6 +228,13 @@ public: void showFirstPage() { _page = HomePage::FIRST; } void poll() override { + if (_dual_radio_enabled_seen != the_mesh.isDualRadioActive()) { + resetRadioProfileDisplayPage(); + } + if (!isPageVisible(_page)) { + _page = HomePage::RADIO; + resetRadioProfileDisplayPage(); + } if (_shutdown_init && !_task->isButtonPressed()) { // must wait for USR button to be released _task->shutdown(); } @@ -297,7 +308,8 @@ public: display.setCursor(display.width() - timestamp_width - 1, y); display.print(tmp); } - } else if (_page == HomePage::RADIO) { + } else if (_page == HomePage::RADIO || _page == HomePage::RADIO2 + || _page == HomePage::RADIO_STATUS) { display.setColor(UIColor::primary_txt); display.setTextSize(1); const auto* radio = the_mesh.getProfileRadio(); @@ -306,13 +318,21 @@ public: const uint8_t status_pages = mesh::ui::radioProfileSystemStatusPageCount( display, dual_radio, 8); uint8_t status_page_index = 0; - if (mesh::ui::showRadioProfileSystemStatusPage(dual_radio, status_pages, - millis() - _radio_profile_page_started_at, &status_page_index)) { + const bool status_page = dual_radio + ? _page == HomePage::RADIO_STATUS + : mesh::ui::showRadioProfileSystemStatusPage( + false, status_pages, + millis() - _radio_profile_page_started_at, + &status_page_index); + if (status_page) { + if (dual_radio && status_pages != 0) { + status_page_index = _radio_status_page % status_pages; + } mesh::ui::drawRadioProfileSystemStatusPage(display, radioProfileSystemStatus(*_node_prefs), status_page_index, 8); - return radioProfileRefreshMillis(); + return dual_radio ? 5000 : radioProfileRefreshMillis(); } - const bool secondary_page = showingSecondaryRadioProfilePage(display); + const bool secondary_page = dual_radio && _page == HomePage::RADIO2; const uint8_t profile = dual_radio && secondary_page ? 1 : 0; float freq = _node_prefs->freq; float bw = _node_prefs->bw; @@ -506,25 +526,26 @@ public: // display.drawTextCentered(display.width() / 2, 40 - 11, "hibernate:" PRESS_LABEL); } } - // Keep the compact radio page on the R1/R2 boundary; other tiny pages - // retain their existing low-refresh cadence. - return _page == HomePage::RADIO ? radioProfileRefreshMillis() : 5000; + return _page == HomePage::RADIO && !the_mesh.isDualRadioActive() + ? radioProfileRefreshMillis() : 5000; } bool handleInput(char c) override { if (c == KEY_LEFT || c == KEY_PREV) { - _page = (_page + HomePage::Count - 1) % HomePage::Count; - if (_page == HomePage::RADIO) resetRadioProfileDisplayPage(); + movePage(-1); return true; } if (c == KEY_NEXT || c == KEY_RIGHT) { - _page = (_page + 1) % HomePage::Count; - if (_page == HomePage::RADIO) resetRadioProfileDisplayPage(); + movePage(1); if (_page == HomePage::RECENT) { _task->showAlert("Recent adverts", 800); } return true; } + if (c == KEY_ENTER && _page == HomePage::RADIO_STATUS) { + _radio_status_page++; + return true; + } if (c == KEY_ENTER && _page == HomePage::BLUETOOTH) { if (_task->isBluetoothEnabled()) { // toggle Bluetooth on/off _task->disableBluetooth();