feat(ui): page radio and system status

This commit is contained in:
mikecarper
2026-09-21 15:35:46 -07:00
parent 527bc98da2
commit a95f7b3d16
28 changed files with 2075 additions and 73 deletions
+118 -5
View File
@@ -2,6 +2,57 @@
#include "target.h"
#include <Arduino.h>
#include <helpers/CommonCLI.h>
#include <helpers/ui/RadioProfileDisplayPage.h>
#include <helpers/ui/RadioProfileSystemStatus.h>
#include <RadioProfiles.h>
#include "SensorMesh.h"
namespace {
const mesh::RadioProfiles* configuredRadioProfiles() {
const auto* radio = activeSensorMesh().getProfileRadio();
return radio ? radio->profiles() : NULL;
}
mesh::ui::RadioProfileSystemStatus radioProfileSystemStatus(
const NodePrefs& prefs) {
mesh::ui::RadioProfileSystemStatus status;
const auto* profiles = configuredRadioProfiles();
status.public_key = activeSensorMesh().getSelfId().pub_key;
status.powersaving_enabled = prefs.powersaving_enabled != 0;
#if ENV_INCLUDE_GPS == 1
status.gps_enabled = prefs.gps_enabled != 0;
#endif
status.fem_enabled = board.canControlLoRaFemLna()
&& board.isLoRaFemLnaEnabled();
status.rx_boosted_gain = prefs.rx_boosted_gain != 0;
status.rx_powersaving_enabled = prefs.rx_powersaving_enabled != 0;
status.cad_enabled = prefs.cad_enabled != 0;
status.dual_radio_enabled = profiles != NULL && profiles->enabled();
if (status.dual_radio_enabled) {
status.secondary_temporary = profiles->secondary_temporary;
status.secondary_mode = profiles->secondary.mode;
status.cross = profiles->cross;
}
status.noise_floor_1 = radio_driver.getNoiseFloorDbm(0);
status.noise_floor_1_seconds =
radio_driver.getNoiseFloorCalibrationSecondsRemaining(0);
if (status.dual_radio_enabled) {
status.noise_floor_2 = radio_driver.getNoiseFloorDbm(1);
status.noise_floor_2_seconds =
radio_driver.getNoiseFloorCalibrationSecondsRemaining(1);
}
return status;
}
uint8_t radioProfileStatusPageCount(DisplayDriver& display,
bool dual_radio_enabled) {
display.setTextSize(1);
return mesh::ui::radioProfileSystemStatusPageCount(display,
dual_radio_enabled);
}
} // namespace
#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
@@ -29,6 +80,7 @@ static const uint8_t meshcore_logo [] PROGMEM = {
void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* firmware_version) {
_prevBtnState = HIGH;
_node_prefs = node_prefs;
resetRadioProfileDisplayPage();
_display->servicePower(board.isExternalPowered() || board.isUsbHostConnected());
#if defined(PIN_USER_BTN) && defined(DISPLAY_CLASS) \
&& defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP) \
@@ -49,6 +101,25 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
free(version);
}
void UITask::resetRadioProfileDisplayPage() {
_radio_profile_page_started_at = millis();
_dual_radio_enabled_seen = activeSensorMesh().isDualRadioActive();
}
bool UITask::showingSecondaryRadioProfilePage() {
const bool dual_radio_enabled = activeSensorMesh().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;
}
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);
}
void UITask::renderCurrScreen() {
char tmp[80];
if (millis() < BOOT_SCREEN_MILLIS) { // boot screen
@@ -77,26 +148,66 @@ void UITask::renderCurrScreen() {
_display->setCursor((_display->width() - typeWidth) / 2, 48);
_display->print(node_type);
} else { // home screen
const bool dual_radio_enabled = activeSensorMesh().isDualRadioActive();
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)) {
mesh::ui::drawRadioProfileSystemStatusPage(*_display,
radioProfileSystemStatus(*_node_prefs), status_page_index);
return;
}
// node name
_display->setCursor(0, 0);
_display->setTextSize(1);
_display->setColor(UIColor::primary_txt);
_display->print(_node_prefs->node_name);
// freq / sf
const mesh::RadioProfiles* profiles = configuredRadioProfiles();
const bool secondary_page = showingSecondaryRadioProfilePage();
const bool dual_radio = profiles != NULL && profiles->enabled();
float freq = _node_prefs->freq;
float bw = _node_prefs->bw;
uint8_t sf = _node_prefs->sf;
uint8_t cr = _node_prefs->cr;
const char* profile_tag = "";
if (dual_radio) {
const uint8_t profile = secondary_page ? 1 : 0;
const auto& params = profiles->params(profile);
freq = params.freq;
bw = params.bw;
sf = params.sf;
cr = params.cr;
profile_tag = mesh::ui::radioProfileDisplayTag(profile,
profile == 1 ? profiles->secondary_temporary : profiles->primary_temporary);
}
// Compact R1/R2 rows preserve every RF field on 128px displays.
_display->setCursor(0, 20);
sprintf(tmp, "FREQ: %06.3f SF%d", _node_prefs->freq, _node_prefs->sf);
if (dual_radio) {
snprintf(tmp, sizeof(tmp), "%s F:%06.3f S:%d", profile_tag, freq, sf);
} else {
snprintf(tmp, sizeof(tmp), "FREQ: %06.3f SF%d", freq, sf);
}
_display->print(tmp);
// bw / cr
_display->setCursor(0, 30);
sprintf(tmp, "BW: %03.2f CR: %d", _node_prefs->bw, _node_prefs->cr);
if (dual_radio) {
snprintf(tmp, sizeof(tmp), "%s B:%03.2f C:%d", profile_tag, bw, cr);
} else {
snprintf(tmp, sizeof(tmp), "BW: %03.2f CR: %d", bw, cr);
}
_display->print(tmp);
}
}
void UITask::loop() {
if (_display->servicePower(board.isExternalPowered() || board.isUsbHostConnected())) _next_refresh = 0;
if (_display->servicePower(board.isExternalPowered() || board.isUsbHostConnected())) {
resetRadioProfileDisplayPage();
_next_refresh = 0;
}
#if defined(PIN_USER_BTN) && defined(DISPLAY_CLASS) \
&& defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP) \
&& MOMENTARY_BUTTON_WAKE_FROM_SLEEP
@@ -104,6 +215,7 @@ void UITask::loop() {
if (ev != BUTTON_EVENT_NONE) {
if (!_display->isOn()) {
_display->wake(mesh::ui::DisplayWake::Button);
resetRadioProfileDisplayPage();
_next_refresh = 0;
}
_display->wake(mesh::ui::DisplayWake::Button);
@@ -117,6 +229,7 @@ void UITask::loop() {
// TODO: any action ?
} else {
_display->wake(mesh::ui::DisplayWake::Button);
resetRadioProfileDisplayPage();
}
_display->wake(mesh::ui::DisplayWake::Button); // extend auto-off timer
}