Unify Heltec V4 OLED, TFT and headless display selection
Detect OLED or the original stock TFT touch assembly in ordinary V4.2/V4.3 images. Add saved live display.type auto/oled/tft/off selection and report the active selection in board output. Keep sensors on primary I2C, preserve shared power, and isolate TFT FSPI from radio HSPI through sleep and changes. Consolidate future picker/build choices only with application capability proof. Retain exact legacy OTA identities and separate R8 hardware images. Document controls and physical qualification limits. Validation: five serialized Full builds with capability/size/RAM checks; focused host tests, existing R8/T-Deck/OLED regressions, build-profile suite, and picker/provider tests. V4.3 OLED live changes and off/auto reboot persistence passed on Mercerwood. Physical TFT qualification remains pending.
This commit is contained in:
1 parent
5b5708283d
commit
b00d346df7
43 files changed
+2123
-76
No files matched your search
@@ -5,6 +5,9 @@
|
||||
#endif
|
||||
#include <helpers/LedSettings.h>
|
||||
#include <helpers/ui/DisplayPowerSettings.h>
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED && defined(DISPLAY_CLASS)
|
||||
#include <helpers/ui/HeltecV4DisplaySettings.h>
|
||||
#endif
|
||||
#include <helpers/ui/DisplayNightLocation.h>
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT && defined(DISPLAY_CLASS)
|
||||
#include <helpers/ui/OLEDControllerSettings.h>
|
||||
@@ -4526,6 +4529,9 @@ bool MyMesh::handleLocalControlCommand(const char* command, char* reply,
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED && defined(DISPLAY_CLASS)
|
||||
if (mesh::ui::handleHeltecV4DisplayCommand(command, reply, reply_size, display)) return true;
|
||||
#endif
|
||||
if (mesh::ui::handleDisplayPowerCommand(command, reply, reply_size,
|
||||
_ui != nullptr && _ui->supportsInboxModes())) {
|
||||
if (_ui) _ui->inboxModeChanged();
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include <Arduino.h> // needed for PlatformIO
|
||||
#include <helpers/ui/StartupScreen.h>
|
||||
#include <helpers/ui/DisplayPowerSettings.h>
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED && defined(DISPLAY_CLASS)
|
||||
#include <helpers/ui/HeltecV4DisplaySettings.h>
|
||||
#endif
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT
|
||||
#include <helpers/ui/OLEDControllerSettings.h>
|
||||
#endif
|
||||
@@ -2080,6 +2083,12 @@ void halt() {
|
||||
|
||||
void formatCompanionWiFiDisplayStatus(char* reply, size_t reply_size) {
|
||||
if (reply == nullptr || reply_size == 0) return;
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED \
|
||||
&& defined(DISPLAY_CLASS)
|
||||
companion_display_available =
|
||||
display.selectedType() != mesh::ui::HeltecV4DisplayType::None;
|
||||
companion_display_begin_status = companion_display_available ? 1 : 0;
|
||||
#endif
|
||||
static const char* const names[] = {
|
||||
"not-rendered", "setup", "off", "ready", "not-configured",
|
||||
"connecting",
|
||||
@@ -3691,6 +3700,9 @@ void setup() {
|
||||
if (!mesh::storage::internalPrimaryFilesystemReady(primary_fs_boot)
|
||||
&& !store.isVolatilePrimaryFS()) display_prefs_fs = nullptr;
|
||||
#endif
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
mesh::ui::loadHeltecV4DisplaySettings(regulator_prefs_fs, display);
|
||||
#endif
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT
|
||||
mesh::ui::loadOLEDControllerSettings(regulator_prefs_fs);
|
||||
#endif
|
||||
@@ -4153,6 +4165,11 @@ void setup() {
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
// Retain the wrapper dependency in headless mode so live selection can
|
||||
// enable a screen. The UI skips rendering while no backend is selected.
|
||||
disp = &display;
|
||||
#endif
|
||||
ui_task.begin(disp, &sensors, the_mesh.getNodePrefs()); // still want to pass this in as dependency, as prefs might be moved
|
||||
#endif
|
||||
#if defined(WIO_E5_MINI_HEADLESS_COMPANION_UI) && defined(PIN_USER_BTN)
|
||||
|
||||
@@ -59,6 +59,15 @@
|
||||
|
||||
#define LONG_PRESS_MILLIS 1200
|
||||
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED \
|
||||
&& !defined(AUTO_SHUTDOWN_MILLIVOLTS)
|
||||
// The original TFT Full recipe includes this battery protection. Retain it
|
||||
// when the canonical V4 image detects that assembly without changing the
|
||||
// historical OLED/headless Full policy.
|
||||
#define AUTO_SHUTDOWN_MILLIVOLTS 3400
|
||||
#define HELTEC_V4_TFT_SHUTDOWN_ONLY 1
|
||||
#endif
|
||||
|
||||
static uint64_t companionMessageNowMillis() {
|
||||
#if defined(ESP32)
|
||||
// Unlike Arduino millis(), this does not wrap after roughly 49.7 days.
|
||||
@@ -2767,6 +2776,18 @@ void UITask::syncAlertPreferences() {
|
||||
|
||||
void UITask::loop() {
|
||||
syncAlertPreferences();
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
static uint32_t display_generation = 0;
|
||||
if (display_generation != display.generation()) {
|
||||
display_generation = display.generation();
|
||||
display.setRotationDegrees(_node_prefs->display_rotation_degrees);
|
||||
_next_refresh = millis();
|
||||
}
|
||||
// Preserve normal headless button, notification and battery behavior while
|
||||
// retaining the wrapper for a later live display.type change.
|
||||
_display = display.selectedType() == mesh::ui::HeltecV4DisplayType::None
|
||||
? nullptr : &display;
|
||||
#endif
|
||||
// Observe startup expiry even while display/Morse/input defers rendering.
|
||||
if (!_startup_complete && static_cast<uint32_t>(millis() - ui_started_at) >= 8000u) {
|
||||
_startup_complete = true;
|
||||
@@ -3037,7 +3058,11 @@ void UITask::loop() {
|
||||
#ifdef AUTO_SHUTDOWN_MILLIVOLTS
|
||||
if (static_cast<int32_t>(millis() - next_batt_chck) >= 0) {
|
||||
uint16_t milliVolts = getBattMilliVolts();
|
||||
if (milliVolts > 0 && milliVolts < AUTO_SHUTDOWN_MILLIVOLTS) {
|
||||
if (milliVolts > 0 && milliVolts < AUTO_SHUTDOWN_MILLIVOLTS
|
||||
#ifdef HELTEC_V4_TFT_SHUTDOWN_ONLY
|
||||
&& display.selectedType() == mesh::ui::HeltecV4DisplayType::Tft
|
||||
#endif
|
||||
) {
|
||||
if(!board.isExternalPowered()) {
|
||||
if (_display != NULL) {
|
||||
_display->startFrame();
|
||||
|
||||
@@ -867,6 +867,19 @@ void UITask::toggleDisplay(const char* source) {
|
||||
#endif
|
||||
|
||||
void UITask::loop() {
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
static uint32_t display_generation = 0;
|
||||
if (display_generation != display.generation()) {
|
||||
display_generation = display.generation();
|
||||
_next_refresh = millis();
|
||||
#ifdef DISPLAY_REDRAW_ON_CHANGE
|
||||
_frame_valid = false;
|
||||
#endif
|
||||
#ifdef DISPLAY_ACTIVITY_DASHBOARD
|
||||
_rows_valid = false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if defined(HELTEC_V4_R8_TFT) && defined(HELTEC_TFT_RUNTIME_ROTATION) && HELTEC_TFT_RUNTIME_ROTATION == 1
|
||||
applyDisplayRotation();
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include <helpers/IdentityGeneration.h>
|
||||
#include <helpers/ui/StartupScreen.h>
|
||||
#include <helpers/ui/DisplayPowerSettings.h>
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED && defined(DISPLAY_CLASS)
|
||||
#include <helpers/ui/HeltecV4DisplaySettings.h>
|
||||
#endif
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT
|
||||
#include <helpers/ui/OLEDControllerSettings.h>
|
||||
#endif
|
||||
@@ -229,6 +232,9 @@ void setup() {
|
||||
#ifdef DISPLAY_CLASS
|
||||
mesh::hilStartupTrace("display_begin");
|
||||
mesh::ui::loadDisplayPowerSettings(fs, false);
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
mesh::ui::loadHeltecV4DisplaySettings(regulator_prefs_fs, display);
|
||||
#endif
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT
|
||||
mesh::ui::loadOLEDControllerSettings(regulator_prefs_fs);
|
||||
#endif
|
||||
@@ -405,6 +411,11 @@ void setup() {
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
// Initialize the UI dependency even when auto detection found no screen.
|
||||
// A later saved display.type change can enable it without restarting.
|
||||
display_ready = true;
|
||||
#endif
|
||||
if (display_ready) {
|
||||
mesh::hilStartupTrace("display_task_begin");
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
@@ -641,7 +652,11 @@ void loop() {
|
||||
const bool morse_timing = mesh::morseTimingActive(&radio_driver);
|
||||
if (!morse_timing) sensors.loop();
|
||||
#ifdef DISPLAY_CLASS
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
if (display.selectedType() != mesh::ui::HeltecV4DisplayType::None) ui_task.loop();
|
||||
#else
|
||||
if (display_ready) ui_task.loop();
|
||||
#endif
|
||||
#endif
|
||||
rtc_clock.tick();
|
||||
if (mesh::serviceUsbLoggingWatchdog(usbLoggingRecoverySafe)) board.reboot();
|
||||
|
||||
@@ -518,6 +518,19 @@ void UITask::toggleDisplay(const char* source) {
|
||||
#endif
|
||||
|
||||
void UITask::loop() {
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
static uint32_t display_generation = 0;
|
||||
if (display_generation != display.generation()) {
|
||||
display_generation = display.generation();
|
||||
_next_refresh = millis();
|
||||
#ifdef DISPLAY_REDRAW_ON_CHANGE
|
||||
_frame_valid = false;
|
||||
#endif
|
||||
#ifdef DISPLAY_ACTIVITY_DASHBOARD
|
||||
_rows_valid = false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if defined(HELTEC_V4_R8_TFT) && defined(HELTEC_TFT_RUNTIME_ROTATION) && HELTEC_TFT_RUNTIME_ROTATION == 1
|
||||
applyDisplayRotation();
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include <helpers/IdentityGeneration.h>
|
||||
#include <helpers/ui/StartupScreen.h>
|
||||
#include <helpers/ui/DisplayPowerSettings.h>
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED && defined(DISPLAY_CLASS)
|
||||
#include <helpers/ui/HeltecV4DisplaySettings.h>
|
||||
#endif
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT
|
||||
#include <helpers/ui/OLEDControllerSettings.h>
|
||||
#endif
|
||||
@@ -161,6 +164,9 @@ void setup() {
|
||||
mesh::RadioProfileCLI::configureBootTuning(regulator_prefs_fs, radio_driver);
|
||||
#ifdef DISPLAY_CLASS
|
||||
mesh::ui::loadDisplayPowerSettings(fs, false);
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
mesh::ui::loadHeltecV4DisplaySettings(regulator_prefs_fs, display);
|
||||
#endif
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT
|
||||
mesh::ui::loadOLEDControllerSettings(regulator_prefs_fs);
|
||||
#endif
|
||||
@@ -279,6 +285,11 @@ void setup() {
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
// Initialize the UI dependency even when auto detection found no screen.
|
||||
// A later saved display.type change can enable it without restarting.
|
||||
display_ready = true;
|
||||
#endif
|
||||
if (display_ready) {
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
ui_task.setObserverPrefs(the_mesh.getObserverPrefs());
|
||||
@@ -415,7 +426,11 @@ void loop() {
|
||||
const bool morse_timing = mesh::morseTimingActive(&radio_driver);
|
||||
if (!morse_timing) sensors.loop();
|
||||
#ifdef DISPLAY_CLASS
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
if (display.selectedType() != mesh::ui::HeltecV4DisplayType::None) ui_task.loop();
|
||||
#else
|
||||
if (display_ready) ui_task.loop();
|
||||
#endif
|
||||
#endif
|
||||
rtc_clock.tick();
|
||||
mesh::power::serviceRegulatorSettings();
|
||||
|
||||
@@ -226,6 +226,19 @@ void UITask::renderCurrScreen() {
|
||||
}
|
||||
|
||||
void UITask::loop() {
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
static uint32_t display_generation = 0;
|
||||
if (display_generation != display.generation()) {
|
||||
display_generation = display.generation();
|
||||
_last_refresh = millis() - 1000u;
|
||||
#ifdef DISPLAY_REDRAW_ON_CHANGE
|
||||
_frame_valid = false;
|
||||
#endif
|
||||
#ifdef DISPLAY_ACTIVITY_DASHBOARD
|
||||
_rows_valid = false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if defined(HELTEC_V4_R8_TFT) && defined(HELTEC_TFT_RUNTIME_ROTATION) && HELTEC_TFT_RUNTIME_ROTATION == 1
|
||||
applyDisplayRotation();
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <helpers/IdentityGeneration.h>
|
||||
#include <helpers/ui/StartupScreen.h>
|
||||
#include <helpers/ui/DisplayPowerSettings.h>
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED && defined(DISPLAY_CLASS)
|
||||
#include <helpers/ui/HeltecV4DisplaySettings.h>
|
||||
#endif
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT
|
||||
#include <helpers/ui/OLEDControllerSettings.h>
|
||||
#endif
|
||||
@@ -179,6 +182,9 @@ void setup() {
|
||||
mesh::RadioProfileCLI::configureBootTuning(regulator_prefs_fs, radio_driver);
|
||||
#ifdef DISPLAY_CLASS
|
||||
mesh::ui::loadDisplayPowerSettings(fs, false);
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
mesh::ui::loadHeltecV4DisplaySettings(regulator_prefs_fs, display);
|
||||
#endif
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT
|
||||
mesh::ui::loadOLEDControllerSettings(regulator_prefs_fs);
|
||||
#endif
|
||||
@@ -294,6 +300,11 @@ void setup() {
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
// Initialize the UI dependency even when auto detection found no screen.
|
||||
// A later saved display.type change can enable it without restarting.
|
||||
display_ready = true;
|
||||
#endif
|
||||
if (display_ready) {
|
||||
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
|
||||
}
|
||||
@@ -376,7 +387,11 @@ void loop() {
|
||||
const bool morse_timing = mesh::morseTimingActive(&radio_driver);
|
||||
if (!morse_timing) sensors.loop();
|
||||
#ifdef DISPLAY_CLASS
|
||||
#if defined(HELTEC_V4_DISPLAY_UNIFIED) && HELTEC_V4_DISPLAY_UNIFIED
|
||||
if (display.selectedType() != mesh::ui::HeltecV4DisplayType::None) ui_task.loop();
|
||||
#else
|
||||
if (display_ready) ui_task.loop();
|
||||
#endif
|
||||
#endif
|
||||
rtc_clock.tick();
|
||||
if (mesh::serviceUsbLoggingWatchdog(usbLoggingRecoverySafe)) board.reboot();
|
||||
|
||||
Reference in new issue
Block a user