diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml
index 3e8b4c001c..51bef0c132 100644
--- a/.github/workflows/build_native.yml
+++ b/.github/workflows/build_native.yml
@@ -10,7 +10,7 @@ jobs:
build-native:
runs-on: ubuntu-latest
steps:
- - name: Install libbluetooth
+ - name: Install libs needed for native build
shell: bash
run: |
sudo apt-get update --fix-missing
diff --git a/src/GpioLogic.cpp b/src/GpioLogic.cpp
index d164615a7b..cbe26fc600 100644
--- a/src/GpioLogic.cpp
+++ b/src/GpioLogic.cpp
@@ -10,6 +10,13 @@ void GpioVirtPin::set(bool value)
}
}
+void GpioHwPin::set(bool value)
+{
+ // if (num == 3) LOG_DEBUG("Setting pin %d to %d\n", num, value);
+ pinMode(num, OUTPUT);
+ digitalWrite(num, value);
+}
+
GpioTransformer::GpioTransformer(GpioPin *outPin) : outPin(outPin) {}
void GpioTransformer::set(bool value)
@@ -17,7 +24,7 @@ void GpioTransformer::set(bool value)
outPin->set(value);
}
-GpioNotTransformer::GpioNotTransformer(GpioVirtPin *inPin, GpioPin *outPin) : GpioTransformer(outPin), inPin(inPin)
+GpioUnaryTransformer::GpioUnaryTransformer(GpioVirtPin *inPin, GpioPin *outPin) : GpioTransformer(outPin), inPin(inPin)
{
assert(!inPin->dependentPin); // We only allow one dependent pin
inPin->dependentPin = this;
@@ -27,6 +34,18 @@ GpioNotTransformer::GpioNotTransformer(GpioVirtPin *inPin, GpioPin *outPin) : Gp
// update();
}
+/**
+ * Update the output pin based on the current state of the input pin.
+ */
+void GpioUnaryTransformer::update()
+{
+ auto p = inPin->get();
+ if (p == GpioVirtPin::PinState::Unset)
+ return; // Not yet fully initialized
+
+ set(p);
+}
+
/**
* Update the output pin based on the current state of the input pin.
*/
@@ -69,6 +88,7 @@ void GpioBinaryTransformer::update()
newValue = (GpioVirtPin::PinState)(p1 && p2);
break;
case Or:
+ // LOG_DEBUG("Doing GPIO OR\n");
newValue = (GpioVirtPin::PinState)(p1 || p2);
break;
case Xor:
diff --git a/src/GpioLogic.h b/src/GpioLogic.h
index 27e85d55b4..947d49625a 100644
--- a/src/GpioLogic.h
+++ b/src/GpioLogic.h
@@ -29,7 +29,7 @@ class GpioHwPin : public GpioPin
public:
explicit GpioHwPin(uint32_t num) : num(num) {}
- void set(bool value) { digitalWrite(num, value); }
+ void set(bool value);
};
class GpioTransformer;
@@ -42,7 +42,7 @@ class GpioBinaryTransformer;
class GpioVirtPin : public GpioPin
{
friend class GpioBinaryTransformer;
- friend class GpioNotTransformer;
+ friend class GpioUnaryTransformer;
public:
enum PinState { On = true, Off = false, Unset = 2 };
@@ -79,12 +79,12 @@ class GpioTransformer
};
/**
- * A transformer that performs a unary NOT operation from an input.
+ * A transformer that just drives a hw pin based on a virtual pin.
*/
-class GpioNotTransformer : public GpioTransformer
+class GpioUnaryTransformer : public GpioTransformer
{
public:
- GpioNotTransformer(GpioVirtPin *inPin, GpioPin *outPin);
+ GpioUnaryTransformer(GpioVirtPin *inPin, GpioPin *outPin);
protected:
friend class GpioVirtPin;
@@ -92,12 +92,28 @@ class GpioNotTransformer : public GpioTransformer
/**
* Update the output pin based on the current state of the input pin.
*/
- void update();
+ virtual void update();
- private:
GpioVirtPin *inPin;
};
+/**
+ * A transformer that performs a unary NOT operation from an input.
+ */
+class GpioNotTransformer : public GpioUnaryTransformer
+{
+ public:
+ GpioNotTransformer(GpioVirtPin *inPin, GpioPin *outPin) : GpioUnaryTransformer(inPin, outPin) {}
+
+ protected:
+ friend class GpioVirtPin;
+
+ /**
+ * Update the output pin based on the current state of the input pin.
+ */
+ void update();
+};
+
/**
* A transformer that combines multiple virtual pins to drive an output pin
*/
diff --git a/src/Power.cpp b/src/Power.cpp
index d63c43137e..61a6c987d4 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -136,6 +136,30 @@ using namespace meshtastic;
*/
static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level sensor
+static void adcEnable()
+{
+#ifdef ADC_CTRL // enable adc voltage divider when we need to read
+#ifdef ADC_USE_PULLUP
+ pinMode(ADC_CTRL, INPUT_PULLUP);
+#else
+ pinMode(ADC_CTRL, OUTPUT);
+ digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED);
+#endif
+ delay(10);
+#endif
+}
+
+static void adcDisable()
+{
+#ifdef ADC_CTRL // disable adc voltage divider when we need to read
+#ifdef ADC_USE_PULLUP
+ pinMode(ADC_CTRL, INPUT_PULLDOWN);
+#else
+ digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED);
+#endif
+#endif
+}
+
/**
* A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input
*/
@@ -226,25 +250,19 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint32_t raw = 0;
float scaled = 0;
+ adcEnable();
#ifdef ARCH_ESP32 // ADC block for espressif platforms
raw = espAdcRead();
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
scaled *= operativeAdcMultiplier;
-#else // block for all other platforms
-#ifdef ADC_CTRL // enable adc voltage divider when we need to read
- pinMode(ADC_CTRL, OUTPUT);
- digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED);
- delay(10);
-#endif
+#else // block for all other platforms
for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += analogRead(BATTERY_PIN);
}
raw = raw / BATTERY_SENSE_SAMPLES;
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
-#ifdef ADC_CTRL // disable adc voltage divider when we need to read
- digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED);
-#endif
#endif
+ adcDisable();
if (!initial_read_done) {
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
@@ -275,11 +293,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint8_t raw_c = 0; // raw reading counter
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
-#ifdef ADC_CTRL // enable adc voltage divider when we need to read
- pinMode(ADC_CTRL, OUTPUT);
- digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED);
- delay(10);
-#endif
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
int val_ = adc1_get_raw(adc_channel);
if (val_ >= 0) { // save only valid readings
@@ -288,18 +301,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
}
// delayMicroseconds(100);
}
-#ifdef ADC_CTRL // disable adc voltage divider when we need to read
- digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED);
-#endif
-#else // ADC2
-#ifdef ADC_CTRL
-#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0)
- pinMode(ADC_CTRL, OUTPUT);
- digitalWrite(ADC_CTRL, LOW); // ACTIVE LOW
- delay(10);
-#endif
-#endif // End ADC_CTRL
-
+#else // ADC2
#ifdef CONFIG_IDF_TARGET_ESP32S3 // ESP32S3
// ADC2 wifi bug workaround not required, breaks compile
// On ESP32S3, ADC2 can take turns with Wifi (?)
@@ -334,12 +336,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
}
#endif // BAT_MEASURE_ADC_UNIT
-#ifdef ADC_CTRL
-#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0)
- digitalWrite(ADC_CTRL, HIGH);
-#endif
-#endif // End ADC_CTRL
-
#endif // End BAT_MEASURE_ADC_UNIT
return (raw / (raw_c < 1 ? 1 : raw_c));
}
diff --git a/src/configuration.h b/src/configuration.h
index 2e0efffd49..047dbd7275 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -177,6 +177,11 @@ along with this program. If not, see .
/* Step #1: offer chance for variant-specific defines */
#include "variant.h"
+#if defined(VEXT_ENABLE) && !defined(VEXT_ON_VALUE)
+// Older variant.h files might not be defining this value, so stay with the old default
+#define VEXT_ON_VALUE LOW
+#endif
+
#ifndef GPS_BAUDRATE
#define GPS_BAUDRATE 9600
#endif
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index 7d7de8700e..12ef34c52e 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -2,6 +2,7 @@
#if !MESHTASTIC_EXCLUDE_GPS
#include "Default.h"
#include "GPS.h"
+#include "GpioLogic.h"
#include "NodeDB.h"
#include "PowerMon.h"
#include "RTC.h"
@@ -875,16 +876,8 @@ void GPS::writePinEN(bool on)
if (HW_VENDOR == meshtastic_HardwareModel_RAK4631 && (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1))
return;
- // Abort: if pin unset
- if (!en_gpio)
- return;
-
- // Determine new value for the pin
- bool val = GPS_EN_ACTIVE ? on : !on;
-
// Write and log
- pinMode(en_gpio, OUTPUT);
- digitalWrite(en_gpio, val);
+ enablePin->set(on);
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("Pin EN %s\n", val == HIGH ? "HIGH" : "LOW");
#endif
@@ -1421,7 +1414,20 @@ GPS *GPS::createGps()
GPS *new_gps = new GPS;
new_gps->rx_gpio = _rx_gpio;
new_gps->tx_gpio = _tx_gpio;
- new_gps->en_gpio = _en_gpio;
+
+ GpioVirtPin *virtPin = new GpioVirtPin();
+ new_gps->enablePin = virtPin; // Always at least populate a virtual pin
+ if (_en_gpio) {
+ GpioPin *p = new GpioHwPin(_en_gpio);
+
+ if (!GPS_EN_ACTIVE) { // Need to invert the pin before hardware
+ new GpioNotTransformer(
+ virtPin, p); // We just leave this created object on the heap so it can stay watching virtPin and driving en_gpio
+ } else {
+ new GpioUnaryTransformer(
+ virtPin, p); // We just leave this created object on the heap so it can stay watching virtPin and driving en_gpio
+ }
+ }
#ifdef PIN_GPS_PPS
// pulse per second
diff --git a/src/gps/GPS.h b/src/gps/GPS.h
index 96171cba52..c0e9fb8b67 100644
--- a/src/gps/GPS.h
+++ b/src/gps/GPS.h
@@ -3,6 +3,7 @@
#if !MESHTASTIC_EXCLUDE_GPS
#include "GPSStatus.h"
+#include "GpioLogic.h"
#include "Observer.h"
#include "TinyGPS++.h"
#include "concurrency/OSThread.h"
@@ -73,7 +74,6 @@ class GPS : private concurrency::OSThread
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;
- uint32_t en_gpio = 0;
int speedSelect = 0;
int probeTries = 2;
@@ -152,6 +152,13 @@ class GPS : private concurrency::OSThread
meshtastic_Position p = meshtastic_Position_init_default;
+ /** This is normally bound to config.position.gps_en_gpio but some rare boards (like heltec tracker) need more advanced
+ * implementations. Those boards will set this public variable to a custom implementation.
+ *
+ * Normally set by GPS::createGPS()
+ */
+ GpioVirtPin *enablePin = NULL;
+
GPS() : concurrency::OSThread("GPS") {}
virtual ~GPS();
@@ -303,4 +310,4 @@ class GPS : private concurrency::OSThread
};
extern GPS *gps;
-#endif // Exclude GPS
+#endif // Exclude GPS
\ No newline at end of file
diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp
index 8ea90c5232..2849dd9a90 100644
--- a/src/graphics/TFTDisplay.cpp
+++ b/src/graphics/TFTDisplay.cpp
@@ -21,10 +21,6 @@ extern SX1509 gpioExtender;
#if defined(ST7735S)
#include // Graphics and font library for ST7735 driver chip
-#if defined(ST7735_BACKLIGHT_EN) && !defined(TFT_BL)
-#define TFT_BL ST7735_BACKLIGHT_EN
-#endif
-
#ifndef TFT_INVERT
#define TFT_INVERT true
#endif
@@ -91,24 +87,20 @@ class LGFX : public lgfx::LGFX_Device
_panel_instance.config(cfg);
}
+#ifdef TFT_BL
// Set the backlight control
{
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
-#ifdef ST7735_BL_V03
- cfg.pin_bl = ST7735_BL_V03;
-#elif defined(ST7735_BL_V05)
- cfg.pin_bl = ST7735_BL_V05;
-#else
- cfg.pin_bl = ST7735_BL; // Pin number to which the backlight is connected
-#endif
- cfg.invert = true; // true to invert the brightness of the backlight
+ cfg.pin_bl = TFT_BL; // Pin number to which the backlight is connected
+ cfg.invert = true; // true to invert the brightness of the backlight
// cfg.freq = 44100; // PWM frequency of backlight
// cfg.pwm_channel = 1; // PWM channel number to use
_light_instance.config(cfg);
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
}
+#endif
setPanel(&_panel_instance);
}
@@ -131,10 +123,6 @@ static void rak14014_tpIntHandle(void)
#elif defined(ST7789_CS)
#include // Graphics and font library for ST7735 driver chip
-#if defined(ST7789_BACKLIGHT_EN) && !defined(TFT_BL)
-#define TFT_BL ST7789_BACKLIGHT_EN
-#endif
-
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ST7789 _panel_instance;
@@ -204,6 +192,7 @@ class LGFX : public lgfx::LGFX_Device
_panel_instance.config(cfg);
}
+#ifdef ST7789_BL
// Set the backlight control. (delete if not necessary)
{
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
@@ -215,6 +204,7 @@ class LGFX : public lgfx::LGFX_Device
_light_instance.config(cfg);
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
}
+#endif
#if HAS_TOUCHSCREEN
// Configure settings for touch screen control.
@@ -324,6 +314,7 @@ class LGFX : public lgfx::LGFX_Device
_panel_instance.config(cfg);
}
+#ifdef TFT_BL
// Set the backlight control
{
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
@@ -336,6 +327,7 @@ class LGFX : public lgfx::LGFX_Device
_light_instance.config(cfg);
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
}
+#endif
setPanel(&_panel_instance);
}
@@ -521,9 +513,26 @@ static LGFX *tft = nullptr;
extern unPhone unphone;
#endif
+GpioPin *TFTDisplay::backlightEnable = NULL;
+
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{
LOG_DEBUG("TFTDisplay!\n");
+
+#ifdef TFT_BL
+ GpioPin *p = new GpioHwPin(TFT_BL);
+
+ if (!TFT_BACKLIGHT_ON) { // Need to invert the pin before hardware
+ auto virtPin = new GpioVirtPin();
+ new GpioNotTransformer(
+ virtPin, p); // We just leave this created object on the heap so it can stay watching virtPin and driving en_gpio
+ p = virtPin;
+ }
+#else
+ GpioPin *p = new GpioVirtPin(); // Just simulate a pin
+#endif
+ backlightEnable = p;
+
#if ARCH_PORTDUINO
if (settingsMap[displayRotate]) {
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayHeight], settingsMap[configNames::displayWidth]);
@@ -577,24 +586,15 @@ void TFTDisplay::sendCommand(uint8_t com)
// handle display on/off directly
switch (com) {
case DISPLAYON: {
+ // LOG_DEBUG("Display on\n");
+ backlightEnable->set(true);
#if ARCH_PORTDUINO
display(true);
if (settingsMap[displayBacklight] > 0)
digitalWrite(settingsMap[displayBacklight], TFT_BACKLIGHT_ON);
-#elif defined(ST7735_BL_V03)
- digitalWrite(ST7735_BL_V03, TFT_BACKLIGHT_ON);
-#elif defined(ST7735_BL_V05)
- pinMode(ST7735_BL_V05, OUTPUT);
- digitalWrite(ST7735_BL_V05, TFT_BACKLIGHT_ON);
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
tft->wakeup();
tft->powerSaveOff();
-#elif defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
- digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
-#endif
-
-#ifdef VTFT_CTRL_V03
- digitalWrite(VTFT_CTRL_V03, LOW);
#endif
#ifdef VTFT_CTRL
@@ -610,25 +610,17 @@ void TFTDisplay::sendCommand(uint8_t com)
break;
}
case DISPLAYOFF: {
+ // LOG_DEBUG("Display off\n");
+ backlightEnable->set(false);
#if ARCH_PORTDUINO
tft->clear();
if (settingsMap[displayBacklight] > 0)
digitalWrite(settingsMap[displayBacklight], !TFT_BACKLIGHT_ON);
-#elif defined(ST7735_BL_V03)
- digitalWrite(ST7735_BL_V03, !TFT_BACKLIGHT_ON);
-#elif defined(ST7735_BL_V05)
- pinMode(ST7735_BL_V05, OUTPUT);
- digitalWrite(ST7735_BL_V05, !TFT_BACKLIGHT_ON);
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
tft->sleep();
tft->powerSaveOn();
-#elif defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
- digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON);
#endif
-#ifdef VTFT_CTRL_V03
- digitalWrite(VTFT_CTRL_V03, HIGH);
-#endif
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, HIGH);
#endif
@@ -712,20 +704,9 @@ bool TFTDisplay::connect()
tft = new LGFX;
#endif
-#ifdef TFT_BL
- pinMode(TFT_BL, OUTPUT);
- digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
- // pinMode(PIN_3V3_EN, OUTPUT);
- // digitalWrite(PIN_3V3_EN, HIGH);
+ backlightEnable->set(true);
LOG_INFO("Power to TFT Backlight\n");
-#endif
-#ifdef ST7735_BL_V03
- digitalWrite(ST7735_BL_V03, TFT_BACKLIGHT_ON);
-#elif defined(ST7735_BL_V05)
- pinMode(ST7735_BL_V05, OUTPUT);
- digitalWrite(ST7735_BL_V05, TFT_BACKLIGHT_ON);
-#endif
#ifdef UNPHONE
unphone.backlight(true); // using unPhone library
LOG_INFO("Power to TFT Backlight\n");
diff --git a/src/graphics/TFTDisplay.h b/src/graphics/TFTDisplay.h
index 42aa3abff5..38cd53ebb5 100644
--- a/src/graphics/TFTDisplay.h
+++ b/src/graphics/TFTDisplay.h
@@ -1,5 +1,6 @@
#pragma once
+#include
#include
/**
@@ -39,6 +40,14 @@ class TFTDisplay : public OLEDDisplay
*/
void setDetected(uint8_t detected);
+ /**
+ * This is normally managed entirely by TFTDisplay, but some rare applications (heltec tracker) might need to replace the
+ * default GPIO behavior with something a bit more complex.
+ *
+ * We (cruftily) make it static so that variant.cpp can access it without needing a ptr to the TFTDisplay instance.
+ */
+ static GpioPin *backlightEnable;
+
protected:
// the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) override { return 0; }
diff --git a/src/main.cpp b/src/main.cpp
index b7d25e7642..e7261c5fa3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -224,6 +224,11 @@ __attribute__((weak, noinline)) bool loopCanSleep()
return true;
}
+// Weak empty variant initialization function.
+// May be redefined by variant files.
+void lateInitVariant() __attribute__((weak));
+void lateInitVariant() {}
+
/**
* Print info as a structured log message (for automated log processing)
*/
@@ -284,29 +289,9 @@ void setup()
digitalWrite(LORA_TCXO_GPIO, HIGH);
#endif
-#if defined(VEXT_ENABLE_V03)
- pinMode(VEXT_ENABLE_V03, OUTPUT);
- pinMode(ST7735_BL_V03, OUTPUT);
- digitalWrite(VEXT_ENABLE_V03, 0); // turn on the display power and antenna boost
- digitalWrite(ST7735_BL_V03, 1); // display backligth on
- LOG_DEBUG("HELTEC Detect Tracker V1.0\n");
-#elif defined(VEXT_ENABLE_V05)
- pinMode(VEXT_ENABLE_V05, OUTPUT);
- pinMode(ST7735_BL_V05, OUTPUT);
- digitalWrite(VEXT_ENABLE_V05, 1); // turn on the lora antenna boost
- digitalWrite(ST7735_BL_V05, 1); // turn on display backligth
- LOG_DEBUG("HELTEC Detect Tracker V1.1\n");
-#elif defined(VEXT_ENABLE) && defined(VEXT_ON_VALUE)
+#if defined(VEXT_ENABLE)
pinMode(VEXT_ENABLE, OUTPUT);
digitalWrite(VEXT_ENABLE, VEXT_ON_VALUE); // turn on the display power
-#elif defined(VEXT_ENABLE)
- pinMode(VEXT_ENABLE, OUTPUT);
- digitalWrite(VEXT_ENABLE, 0); // turn on the display power
-#endif
-
-#if defined(VTFT_CTRL_V03)
- pinMode(VTFT_CTRL_V03, OUTPUT);
- digitalWrite(VTFT_CTRL_V03, LOW);
#endif
#if defined(VTFT_CTRL)
@@ -1030,6 +1015,8 @@ void setup()
}
}
+ lateInitVariant(); // Do board specific init (see extra_variants/README.md for documentation)
+
#if !MESHTASTIC_EXCLUDE_MQTT
mqttInit();
#endif
@@ -1156,4 +1143,4 @@ void loop()
}
// if (didWake) LOG_DEBUG("wake!\n");
}
-#endif
+#endif
\ No newline at end of file
diff --git a/src/platform/extra_variants/README.md b/src/platform/extra_variants/README.md
new file mode 100644
index 0000000000..e558502f09
--- /dev/null
+++ b/src/platform/extra_variants/README.md
@@ -0,0 +1,15 @@
+# About extra_variants
+
+This directory tree is designed to solve two problems.
+
+- The ESP32 arduino/platformio project doesn't support the nice "if initVariant() is found, call that after init" behavior of the nrf52 builds (they use initVariant() internally).
+- Over the years a lot of 'board specific' init code has been added to init() in main.cpp. It would be great to have a general/clean mechanism to allow developers to specify board specific/unique code in a clean fashion without mucking in main.
+
+So we are borrowing the initVariant() ideas here (by using weak gcc references). You can now define lateInitVariant() if your board needs it.
+
+If you'd like a board specific variant to be run, add the variant.cpp file to an appropriately named
+subdirectory and check for \_VARIANT_boardname in the cpp file (so that your code is only built for your board).
+You'll need to define \_VARIANT_boardname in your corresponding variant.h file.
+See existing boards for examples.
+
+This approach has no added runtime cost.
diff --git a/src/platform/extra_variants/heltec_wireless_tracker/variant.cpp b/src/platform/extra_variants/heltec_wireless_tracker/variant.cpp
new file mode 100644
index 0000000000..84264ef587
--- /dev/null
+++ b/src/platform/extra_variants/heltec_wireless_tracker/variant.cpp
@@ -0,0 +1,34 @@
+#include "configuration.h"
+
+#ifdef _VARIANT_HELTEC_WIRELESS_TRACKER
+
+#include "GPS.h"
+#include "GpioLogic.h"
+#include "graphics/TFTDisplay.h"
+
+// Heltec tracker specific init
+void lateInitVariant()
+{
+ // LOG_DEBUG("Heltec tracker initVariant\n");
+#ifdef VEXT_ENABLE
+ GpioPin *hwEnable = new GpioHwPin(VEXT_ENABLE);
+ GpioVirtPin *virtGpsEnable = gps ? gps->enablePin : new GpioVirtPin();
+
+ // On this board we are actually using the backlightEnable signal to already be controlling a physical enable to the
+ // display controller. But we'd _ALSO_ like to have that signal drive a virtual GPIO. So nest it as needed.
+ GpioVirtPin *virtScreenEnable = new GpioVirtPin();
+ if (TFTDisplay::backlightEnable) {
+ GpioPin *physScreenEnable = TFTDisplay::backlightEnable;
+ GpioPin *splitter = new GpioSplitter(virtScreenEnable, physScreenEnable);
+ TFTDisplay::backlightEnable = splitter;
+
+ // Assume screen is initially powered
+ splitter->set(true);
+ }
+
+ // If either the GPS or the screen is on, turn on the external power regulator
+ new GpioBinaryTransformer(virtGpsEnable, virtScreenEnable, hwEnable, GpioBinaryTransformer::Or);
+#endif
+}
+
+#endif
\ No newline at end of file
diff --git a/src/sleep.cpp b/src/sleep.cpp
index bf50d8ffa7..27e81ce548 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -246,15 +246,8 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power
#endif
-#if defined(VEXT_ENABLE_V03)
- digitalWrite(VEXT_ENABLE_V03, 1); // turn off the display power
-#elif defined(VEXT_ENABLE_V05)
- digitalWrite(VEXT_ENABLE_V05, 0); // turn off the lora amplifier power
- digitalWrite(ST7735_BL_V05, 0); // turn off the display power
-#elif defined(VEXT_ENABLE) && defined(VEXT_ON_VALUE)
+#if defined(VEXT_ENABLE)
digitalWrite(VEXT_ENABLE, !VEXT_ON_VALUE); // turn on the display power
-#elif defined(VEXT_ENABLE)
- digitalWrite(VEXT_ENABLE, 1); // turn off the display power
#endif
#ifdef ARCH_ESP32
diff --git a/variants/chatter2/variant.h b/variants/chatter2/variant.h
index 70438e52ac..b7f9469708 100644
--- a/variants/chatter2/variant.h
+++ b/variants/chatter2/variant.h
@@ -54,7 +54,7 @@
#define ST7735_RESET 15
#define ST7735_MISO -1
#define ST7735_BUSY -1
-#define ST7735_BL 32
+#define TFT_BL 32
#define ST7735_SPI_HOST HSPI_HOST // SPI2_HOST for S3, auto may work too
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
diff --git a/variants/heltec_mesh_node_t114/variant.h b/variants/heltec_mesh_node_t114/variant.h
index f7a2681489..e8c3059902 100644
--- a/variants/heltec_mesh_node_t114/variant.h
+++ b/variants/heltec_mesh_node_t114/variant.h
@@ -49,7 +49,7 @@ extern "C" {
// #define ST7789_BL (32+6)
#define TFT_BACKLIGHT_ON LOW
#define ST7789_SPI_HOST SPI1_HOST
-// #define ST7789_BACKLIGHT_EN (32+6)
+// #define TFT_BL (32+6)
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define TFT_HEIGHT 135
diff --git a/variants/heltec_wireless_paper/variant.h b/variants/heltec_wireless_paper/variant.h
index a7bd460f79..520dcec9b3 100644
--- a/variants/heltec_wireless_paper/variant.h
+++ b/variants/heltec_wireless_paper/variant.h
@@ -22,6 +22,7 @@
// Power
#define VEXT_ENABLE 45 // Active low, powers the E-Ink display
+#define VEXT_ON_VALUE LOW
#define ADC_CTRL 19
#define BATTERY_PIN 20
#define ADC_CHANNEL ADC2_GPIO20_CHANNEL
@@ -29,6 +30,7 @@
#define BAT_MEASURE_ADC_UNIT 2 // Use ADC2
#define ADC_ATTENUATION ADC_ATTEN_DB_12 // Voltage divider output is quite high
#define HAS_32768HZ
+#define ADC_CTRL_ENABLED LOW
// LoRa
#define USE_SX1262
@@ -49,4 +51,4 @@
#define SX126X_RESET LORA_RESET
#define SX126X_DIO2_AS_RF_SWITCH
-#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
\ No newline at end of file
diff --git a/variants/heltec_wireless_paper_v1/variant.h b/variants/heltec_wireless_paper_v1/variant.h
index a7bd460f79..520dcec9b3 100644
--- a/variants/heltec_wireless_paper_v1/variant.h
+++ b/variants/heltec_wireless_paper_v1/variant.h
@@ -22,6 +22,7 @@
// Power
#define VEXT_ENABLE 45 // Active low, powers the E-Ink display
+#define VEXT_ON_VALUE LOW
#define ADC_CTRL 19
#define BATTERY_PIN 20
#define ADC_CHANNEL ADC2_GPIO20_CHANNEL
@@ -29,6 +30,7 @@
#define BAT_MEASURE_ADC_UNIT 2 // Use ADC2
#define ADC_ATTENUATION ADC_ATTEN_DB_12 // Voltage divider output is quite high
#define HAS_32768HZ
+#define ADC_CTRL_ENABLED LOW
// LoRa
#define USE_SX1262
@@ -49,4 +51,4 @@
#define SX126X_RESET LORA_RESET
#define SX126X_DIO2_AS_RF_SWITCH
-#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
\ No newline at end of file
diff --git a/variants/heltec_wireless_tracker/variant.h b/variants/heltec_wireless_tracker/variant.h
index 685c9f0795..79fa0e8010 100644
--- a/variants/heltec_wireless_tracker/variant.h
+++ b/variants/heltec_wireless_tracker/variant.h
@@ -1,5 +1,6 @@
#define LED_PIN 18
+#define _VARIANT_HELTEC_WIRELESS_TRACKER
#define HELTEC_TRACKER_V1_X
// I2C
@@ -15,7 +16,7 @@
#define ST7735_RESET 39
#define ST7735_MISO -1
#define ST7735_BUSY -1
-#define ST7735_BL_V05 21 /* V1.1 PCB marking */
+#define TFT_BL 21 /* V1.1 PCB marking */
#define ST7735_SPI_HOST SPI3_HOST
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
@@ -31,15 +32,17 @@
// GPS UC6580: GPS V_DET(8), VDD_IO(7), DCDC_IN(21), pulls up RESETN(17), D_SEL(33) and BOOT_MODE(34) through 10kR
// GPS LNA SW7125DE: VCC(4), pulls up SHDN(5) through 10kR
// LED: VDD, LEDA (through diode)
-#define VEXT_ENABLE_V05 3 // active HIGH - powers the GPS, GPS LNA and OLED VDD/anode
+
+#define VEXT_ENABLE 3 // active HIGH - powers the GPS, GPS LNA and OLED
+#define VEXT_ON_VALUE HIGH
#define BUTTON_PIN 0
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
#define ADC_MULTIPLIER 4.9 * 1.045
-#define ADC_CTRL 2 // active HIGH, powers the voltage divider. Only on 1.1
-#define ADC_CTRL_ENABLED HIGH
+#define ADC_CTRL 2 // active HIGH, powers the voltage divider. Only on 1.1
+#define ADC_USE_PULLUP // Use internal pullup/pulldown instead of actively driving the output
#undef GPS_RX_PIN
#undef GPS_TX_PIN
@@ -72,4 +75,4 @@
#define SX126X_RESET LORA_RESET
#define SX126X_DIO2_AS_RF_SWITCH
-#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
\ No newline at end of file
diff --git a/variants/heltec_wireless_tracker_V1_0/variant.h b/variants/heltec_wireless_tracker_V1_0/variant.h
index 23987adf02..876ff11465 100644
--- a/variants/heltec_wireless_tracker_V1_0/variant.h
+++ b/variants/heltec_wireless_tracker_V1_0/variant.h
@@ -15,7 +15,7 @@
#define ST7735_RESET 39
#define ST7735_MISO -1
#define ST7735_BUSY -1
-#define ST7735_BL_V03 45
+#define TFT_BL 45
#define ST7735_SPI_HOST SPI3_HOST
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
@@ -24,11 +24,12 @@
#define TFT_WIDTH DISPLAY_HEIGHT
#define TFT_OFFSET_X 26
#define TFT_OFFSET_Y -1
-#define VTFT_CTRL_V03 46 // Heltec Tracker needs this pulled low for TFT
+#define VTFT_CTRL 46 // Heltec Tracker needs this pulled low for TFT
#define SCREEN_TRANSITION_FRAMERATE 3 // fps
#define DISPLAY_FORCE_SMALL_FONTS
-#define VEXT_ENABLE_V03 Vext // active low, powers the oled display and the lora antenna boost
+#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
+#define VEXT_ON_VALUE LOW
#define BUTTON_PIN 0
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
@@ -43,8 +44,7 @@
#define PIN_GPS_RESET 35
#define PIN_GPS_PPS 36
-#define VGNSS_CTRL_V03 37 // Heltec Tracker needs this pulled low for GPS
-#define PIN_GPS_EN VGNSS_CTRL_V03
+#define PIN_GPS_EN 37 // Heltec Tracker needs this pulled low for GPS
#define GPS_EN_ACTIVE LOW
#define GPS_RESET_MODE LOW
@@ -69,4 +69,4 @@
#define SX126X_RESET LORA_RESET
#define SX126X_DIO2_AS_RF_SWITCH
-#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
\ No newline at end of file
diff --git a/variants/heltec_wsl_v3/variant.h b/variants/heltec_wsl_v3/variant.h
index 75cea538d0..c103b91728 100644
--- a/variants/heltec_wsl_v3/variant.h
+++ b/variants/heltec_wsl_v3/variant.h
@@ -4,6 +4,7 @@
#define LED_PIN LED
#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
+#define VEXT_ON_VALUE LOW
#define BUTTON_PIN 0
#define ADC_CTRL 37
@@ -32,4 +33,4 @@
#define SX126X_RESET LORA_RESET
#define SX126X_DIO2_AS_RF_SWITCH
-#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
\ No newline at end of file
diff --git a/variants/lora_relay_v1/variant.h b/variants/lora_relay_v1/variant.h
index 54bc87b68a..6efd711c6c 100644
--- a/variants/lora_relay_v1/variant.h
+++ b/variants/lora_relay_v1/variant.h
@@ -144,7 +144,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define ST7735_RESET (11) // Output
#define ST7735_CS (12)
-#define ST7735_BACKLIGHT_EN (13)
+#define TFT_BL (13)
#define ST7735_RS (9)
// #define LORA_DISABLE_SENDING // The board can brownout during lora TX if you don't have a battery connected. Disable sending
@@ -158,4 +158,4 @@ static const uint8_t SCK = PIN_SPI_SCK;
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
-#endif
+#endif
\ No newline at end of file
diff --git a/variants/lora_relay_v2/variant.h b/variants/lora_relay_v2/variant.h
index 6ef7ad7d6b..f18f810345 100644
--- a/variants/lora_relay_v2/variant.h
+++ b/variants/lora_relay_v2/variant.h
@@ -166,7 +166,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
// ST7565 SPI
#define ST7735_RESET (11) // Output
#define ST7735_CS (12)
-#define ST7735_BACKLIGHT_EN (13)
+#define TFT_BL (13)
#define ST7735_RS (9)
#define ST7735_SDA (39) // actually spi MOSI
#define ST7735_SCK (37) // actually spi clk
@@ -185,4 +185,4 @@ static const uint8_t SCK = PIN_SPI_SCK;
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
-#endif
+#endif
\ No newline at end of file
diff --git a/variants/picomputer-s3/variant.h b/variants/picomputer-s3/variant.h
index fc746c599d..ff8faa6f4e 100644
--- a/variants/picomputer-s3/variant.h
+++ b/variants/picomputer-s3/variant.h
@@ -37,7 +37,7 @@
#define ST7789_MISO -1
#define ST7789_BUSY -1
#define ST7789_SPI_HOST SPI3_HOST
-#define ST7789_BACKLIGHT_EN 5
+#define TFT_BL 5
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define TFT_HEIGHT 320
diff --git a/variants/t-deck/variant.h b/variants/t-deck/variant.h
index 7efa00c825..9860d608f8 100644
--- a/variants/t-deck/variant.h
+++ b/variants/t-deck/variant.h
@@ -8,7 +8,7 @@
#define ST7789_BUSY -1
#define ST7789_BL 42
#define ST7789_SPI_HOST SPI2_HOST
-#define ST7789_BACKLIGHT_EN 42
+#define TFT_BL 42
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define TFT_HEIGHT 320
diff --git a/variants/t-watch-s3/variant.h b/variants/t-watch-s3/variant.h
index ad7e6b56b5..9f939d8594 100644
--- a/variants/t-watch-s3/variant.h
+++ b/variants/t-watch-s3/variant.h
@@ -8,7 +8,7 @@
#define ST7789_BUSY -1
#define ST7789_BL 45
#define ST7789_SPI_HOST SPI3_HOST
-#define ST7789_BACKLIGHT_EN 45
+#define TFT_BL 45
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define TFT_HEIGHT 240
@@ -30,8 +30,6 @@
#define I2C_SDA1 39 // Used for capacitive touch
#define I2C_SCL1 40 // Used for capacitive touch
-#define TFT_BL ST7789_BACKLIGHT_EN
-
#define HAS_I2S
#define DAC_I2S_BCK 48
#define DAC_I2S_WS 15
diff --git a/variants/tlora_v1/variant.h b/variants/tlora_v1/variant.h
index 08fefa809b..83e2c193e4 100644
--- a/variants/tlora_v1/variant.h
+++ b/variants/tlora_v1/variant.h
@@ -4,8 +4,9 @@
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
-#define LED_PIN 2 // If defined we will blink this LED
-#define BUTTON_PIN 0 // If defined, this will be used for user button presses
+#define VEXT_ON_VALUE LOW
+#define LED_PIN 2 // If defined we will blink this LED
+#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define BUTTON_NEED_PULLUP
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Module.
diff --git a/variants/tracksenger/internal/variant.h b/variants/tracksenger/internal/variant.h
index 929c387930..57ead848d3 100644
--- a/variants/tracksenger/internal/variant.h
+++ b/variants/tracksenger/internal/variant.h
@@ -17,7 +17,7 @@
#define ST7735_RESET 39
#define ST7735_MISO -1
#define ST7735_BUSY -1
-#define ST7735_BL_V05 21 /* V1.1 PCB marking */
+#define TFT_BL 21 /* V1.1 PCB marking */
#define ST7735_SPI_HOST SPI3_HOST
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
@@ -29,7 +29,8 @@
#define SCREEN_TRANSITION_FRAMERATE 3 // fps
#define DISPLAY_FORCE_SMALL_FONTS
-#define VEXT_ENABLE_V05 3 // active HIGH, powers the lora antenna boost
+#define VEXT_ENABLE 3 // active HIGH, powers the lora antenna boost
+#define VEXT_ON_VALUE HIGH
#define BUTTON_PIN 0
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
@@ -88,4 +89,4 @@
{ \
26, 37, 17, 16, 15, 7 \
}
-// #end keyboard
+// #end keyboard
\ No newline at end of file
diff --git a/variants/tracksenger/lcd/variant.h b/variants/tracksenger/lcd/variant.h
index 3f952361bb..ecf4e854e9 100644
--- a/variants/tracksenger/lcd/variant.h
+++ b/variants/tracksenger/lcd/variant.h
@@ -16,13 +16,13 @@
#define ST7789_CS 38
#define ST7789_RS 40
#define ST7789_BL 21
-// P#define ST7735_BL_V05 21 /* V1.1 PCB marking */
+// P#define TFT_BL 21 /* V1.1 PCB marking */
#define ST7789_RESET -1
#define ST7789_MISO -1
#define ST7789_BUSY -1
#define ST7789_SPI_HOST SPI3_HOST
-#define ST7789_BACKLIGHT_EN 21
+#define TFT_BL 21
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define TFT_HEIGHT 320
@@ -41,7 +41,7 @@
// #define ST7735_RESET 39
// #define ST7735_MISO -1
// #define ST7735_BUSY -1
-#define ST7735_BL_V05 21 /* V1.1 PCB marking */
+#define TFT_BL 21 /* V1.1 PCB marking */
// #define ST7735_SPI_HOST SPI3_HOST
// #define SPI_FREQUENCY 40000000
// #define SPI_READ_FREQUENCY 16000000
@@ -53,7 +53,8 @@
#define SCREEN_TRANSITION_FRAMERATE 3 // fps
// #define DISPLAY_FORCE_SMALL_FONTS
-#define VEXT_ENABLE_V05 3 // active HIGH, powers the lora antenna boost
+#define VEXT_ENABLE 3 // active HIGH, powers the lora antenna boost
+#define VEXT_ON_VALUE HIGH
#define BUTTON_PIN 0
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
@@ -112,4 +113,4 @@
{ \
26, 37, 17, 16, 15, 7 \
}
-// #end keyboard
+// #end keyboard
\ No newline at end of file
diff --git a/variants/tracksenger/oled/variant.h b/variants/tracksenger/oled/variant.h
index 99f12bd233..70f0f3209f 100644
--- a/variants/tracksenger/oled/variant.h
+++ b/variants/tracksenger/oled/variant.h
@@ -19,7 +19,7 @@
// #define ST7735_RESET 39
// #define ST7735_MISO -1
// #define ST7735_BUSY -1
-#define ST7735_BL_V05 21 /* V1.1 PCB marking */
+#define TFT_BL 21 /* V1.1 PCB marking */
// #define ST7735_SPI_HOST SPI3_HOST
// #define SPI_FREQUENCY 40000000
// #define SPI_READ_FREQUENCY 16000000
@@ -31,7 +31,8 @@
#define SCREEN_TRANSITION_FRAMERATE 3 // fps
// #define DISPLAY_FORCE_SMALL_FONTS
-#define VEXT_ENABLE_V05 3 // active HIGH, powers the lora antenna boost
+#define VEXT_ENABLE 3 // active HIGH, powers the lora antenna boost
+#define VEXT_ON_VALUE HIGH
#define BUTTON_PIN 0
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
@@ -90,4 +91,4 @@
{ \
26, 37, 17, 16, 15, 7 \
}
-// #end keyboard
+// #end keyboard
\ No newline at end of file
diff --git a/variants/wiphone/variant.h b/variants/wiphone/variant.h
index b2b3ade788..cfa5667bb1 100644
--- a/variants/wiphone/variant.h
+++ b/variants/wiphone/variant.h
@@ -34,13 +34,17 @@
#define ST7789_SCK 18
#define ST7789_CS 5
#define ST7789_RS 26
-#define ST7789_BL -1 // EXTENDER_PIN(9)
+// I don't have a 'wiphone' but this I think should not be defined this way (don't set TFT_BL if we don't have a hw way to control
+// it)
+// #define ST7789_BL -1 // EXTENDER_PIN(9)
#define ST7789_RESET -1
#define ST7789_MISO 19
#define ST7789_BUSY -1
#define ST7789_SPI_HOST SPI3_HOST
-#define ST7789_BACKLIGHT_EN -1 // EXTENDER_PIN(9)
+// I don't have a 'wiphone' but this I think should not be defined this way (don't set TFT_BL if we don't have a hw way to control
+// it)
+// #define TFT_BL -1 // EXTENDER_PIN(9)
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define TFT_HEIGHT 240