diff --git a/src/GpioLogic.cpp b/src/GpioLogic.cpp new file mode 100644 index 000000000..d164615a7 --- /dev/null +++ b/src/GpioLogic.cpp @@ -0,0 +1,84 @@ +#include "GpioLogic.h" +#include + +void GpioVirtPin::set(bool value) +{ + if (value != this->value) { + this->value = value ? PinState::On : PinState::Off; + if (dependentPin) + dependentPin->update(); + } +} + +GpioTransformer::GpioTransformer(GpioPin *outPin) : outPin(outPin) {} + +void GpioTransformer::set(bool value) +{ + outPin->set(value); +} + +GpioNotTransformer::GpioNotTransformer(GpioVirtPin *inPin, GpioPin *outPin) : GpioTransformer(outPin), inPin(inPin) +{ + assert(!inPin->dependentPin); // We only allow one dependent pin + inPin->dependentPin = this; + + // Don't update at construction time, because various GpioPins might be global constructor based not yet initied because + // order of operations for global constructors is not defined. + // update(); +} + +/** + * Update the output pin based on the current state of the input pin. + */ +void GpioNotTransformer::update() +{ + auto p = inPin->get(); + if (p == GpioVirtPin::PinState::Unset) + return; // Not yet fully initialized + + set(!p); +} + +GpioBinaryTransformer::GpioBinaryTransformer(GpioVirtPin *inPin1, GpioVirtPin *inPin2, GpioPin *outPin, Operation operation) + : GpioTransformer(outPin), inPin1(inPin1), inPin2(inPin2), operation(operation) +{ + assert(!inPin1->dependentPin); // We only allow one dependent pin + inPin1->dependentPin = this; + assert(!inPin2->dependentPin); // We only allow one dependent pin + inPin2->dependentPin = this; + + // Don't update at construction time, because various GpioPins might be global constructor based not yet initied because + // order of operations for global constructors is not defined. + // update(); +} + +void GpioBinaryTransformer::update() +{ + auto p1 = inPin1->get(), p2 = inPin2->get(); + GpioVirtPin::PinState newValue = GpioVirtPin::PinState::Unset; + + if (p1 == GpioVirtPin::PinState::Unset) + newValue = p2; // Not yet fully initialized + else if (p2 == GpioVirtPin::PinState::Unset) + newValue = p1; // Not yet fully initialized + + // If we've already found our value just use it, otherwise need to do the operation + if (newValue == GpioVirtPin::PinState::Unset) { + switch (operation) { + case And: + newValue = (GpioVirtPin::PinState)(p1 && p2); + break; + case Or: + newValue = (GpioVirtPin::PinState)(p1 || p2); + break; + case Xor: + newValue = (GpioVirtPin::PinState)(p1 != p2); + break; + default: + assert(false); + } + } + set(newValue); +} + +GpioSplitter::GpioSplitter(GpioPin *outPin1, GpioPin *outPin2) : outPin1(outPin1), outPin2(outPin2) {} \ No newline at end of file diff --git a/src/GpioLogic.h b/src/GpioLogic.h new file mode 100644 index 000000000..27e85d55b --- /dev/null +++ b/src/GpioLogic.h @@ -0,0 +1,144 @@ +#pragma once + +#include "configuration.h" + +/**This is a set of classes to mediate access to GPIOs in a structured way. Most usage of GPIOs do not + require these classes! But if your hardware has a GPIO that is 'shared' between multiple devices (i.e. a shared power enable) + then using these classes might be able to let you cleanly turn on that enable when either dependent device is needed. + + Note: these classes are intended to be 99% inline for the common case so should have minimal impact on flash or RAM + requirements. +*/ + +/** + * A logical GPIO pin (not necessary raw hardware). + */ +class GpioPin +{ + public: + virtual void set(bool value) = 0; +}; + +/** + * A physical GPIO hw pin. + */ +class GpioHwPin : public GpioPin +{ + uint32_t num; + + public: + explicit GpioHwPin(uint32_t num) : num(num) {} + + void set(bool value) { digitalWrite(num, value); } +}; + +class GpioTransformer; +class GpioNotTransformer; +class GpioBinaryTransformer; + +/** + * A virtual GPIO pin. + */ +class GpioVirtPin : public GpioPin +{ + friend class GpioBinaryTransformer; + friend class GpioNotTransformer; + + public: + enum PinState { On = true, Off = false, Unset = 2 }; + + void set(bool value); + PinState get() const { return value; } + + private: + PinState value = PinState::Unset; + GpioTransformer *dependentPin = NULL; +}; + +#include + +/** + * A 'smart' trigger that can depend in a fake GPIO and if that GPIO changes, drive some other downstream GPIO to change. + * notably: the set method is not public (because it always is calculated by a subclass) + */ +class GpioTransformer +{ + public: + /** + * Update the output pin based on the current state of the input pin. + */ + virtual void update() = 0; + + protected: + GpioTransformer(GpioPin *outPin); + + void set(bool value); + + private: + GpioPin *outPin; +}; + +/** + * A transformer that performs a unary NOT operation from an input. + */ +class GpioNotTransformer : public GpioTransformer +{ + public: + GpioNotTransformer(GpioVirtPin *inPin, GpioPin *outPin); + + protected: + friend class GpioVirtPin; + + /** + * Update the output pin based on the current state of the input pin. + */ + void update(); + + private: + GpioVirtPin *inPin; +}; + +/** + * A transformer that combines multiple virtual pins to drive an output pin + */ +class GpioBinaryTransformer : public GpioTransformer +{ + + public: + enum Operation { And, Or, Xor }; + + GpioBinaryTransformer(GpioVirtPin *inPin1, GpioVirtPin *inPin2, GpioPin *outPin, Operation operation); + + protected: + friend class GpioVirtPin; + + /** + * Update the output pin based on the current state of the input pins. + */ + void update(); + + private: + GpioVirtPin *inPin1; + GpioVirtPin *inPin2; + Operation operation; +}; + +/** + * Sometimes a single output GPIO single needs to drive multiple physical GPIOs. This class provides that. + */ +class GpioSplitter : public GpioPin +{ + + public: + GpioSplitter(GpioPin *outPin1, GpioPin *outPin2); + + void set(bool value) + { + outPin1->set(value); + outPin2->set(value); + } + + private: + GpioPin *outPin1; + GpioPin *outPin2; +}; \ No newline at end of file diff --git a/src/Led.cpp b/src/Led.cpp new file mode 100644 index 000000000..6406cd2f7 --- /dev/null +++ b/src/Led.cpp @@ -0,0 +1,66 @@ +#include "Led.h" +#include "PowerMon.h" +#include "main.h" +#include "power.h" + +GpioVirtPin ledForceOn, ledBlink; + +#if defined(LED_PIN) +// Most boards have a GPIO for LED control +static GpioHwPin ledRawHwPin(LED_PIN); +#else +static GpioVirtPin ledRawHwPin; // Dummy pin for no hardware +#endif + +#if LED_STATE_ON == 0 +static GpioVirtPin ledHwPin; +static GpioNotTransformer ledInverter(&ledHwPin, &ledRawHwPin); +#else +static GpioPin &ledHwPin = ledRawHwPin; +#endif + +#if defined(HAS_PMU) +/** + * A GPIO controlled by the PMU + */ +class GpioPmuPin : public GpioPin +{ + public: + void set(bool value) + { + if (pmu_found && PMU) { + // blink the axp led + PMU->setChargingLedMode(value ? XPOWERS_CHG_LED_ON : XPOWERS_CHG_LED_OFF); + } + } +} ledPmuHwPin; + +// In some cases we need to drive a PMU LED and a normal LED +static GpioSplitter ledFinalPin(&ledHwPin, &ledPmuHwPin); +#else +static GpioPin &ledFinalPin = ledHwPin; +#endif + +#ifdef USE_POWERMON +/** + * We monitor changes to the LED drive output because we use that as a sanity test in our power monitor stuff. + */ +class MonitoredLedPin : public GpioPin +{ + public: + void set(bool value) + { + if (powerMon) { + if (value) + powerMon->setState(meshtastic_PowerMon_State_LED_On); + else + powerMon->clearState(meshtastic_PowerMon_State_LED_On); + } + ledFinalPin.set(value); + } +} monitoredLedPin; +#else +static GpioPin &monitoredLedPin = ledFinalPin; +#endif + +static GpioBinaryTransformer ledForcer(&ledForceOn, &ledBlink, &monitoredLedPin, GpioBinaryTransformer::Or); \ No newline at end of file diff --git a/src/Led.h b/src/Led.h new file mode 100644 index 000000000..68833e041 --- /dev/null +++ b/src/Led.h @@ -0,0 +1,7 @@ +#include "GpioLogic.h" +#include "configuration.h" + +/** + * ledForceOn and ledForceOff both override the normal ledBlinker behavior (which is controlled by main) + */ +extern GpioVirtPin ledForceOn, ledBlink; \ No newline at end of file diff --git a/src/Power.cpp b/src/Power.cpp index e8e406a94..d63c43137 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -80,9 +80,6 @@ RAK9154Sensor rak9154Sensor; #endif #ifdef HAS_PMU -#include "XPowersAXP192.tpp" -#include "XPowersAXP2101.tpp" -#include "XPowersLibInterface.hpp" XPowersLibInterface *PMU = NULL; #else diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 699a6bca6..0a954c1b8 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -9,6 +9,7 @@ */ #include "PowerFSM.h" #include "Default.h" +#include "Led.h" #include "MeshService.h" #include "NodeDB.h" #include "PowerMon.h" @@ -50,7 +51,6 @@ static bool isPowered() static void sdsEnter() { LOG_DEBUG("Enter state: SDS\n"); - powerMon->setState(meshtastic_PowerMon_State_CPU_DeepSleep); // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false); } @@ -70,7 +70,6 @@ static uint32_t secsSlept; static void lsEnter() { LOG_INFO("lsEnter begin, ls_secs=%u\n", config.power.ls_secs); - powerMon->clearState(meshtastic_PowerMon_State_Screen_On); screen->setOn(false); secsSlept = 0; // How long have we been sleeping this time @@ -91,7 +90,7 @@ static void lsIdle() uint32_t sleepTime = SLEEP_TIME; powerMon->setState(meshtastic_PowerMon_State_CPU_LightSleep); - setLed(false); // Never leave led on while in light sleep + ledBlink.set(false); // Never leave led on while in light sleep esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL); powerMon->clearState(meshtastic_PowerMon_State_CPU_LightSleep); @@ -99,7 +98,7 @@ static void lsIdle() case ESP_SLEEP_WAKEUP_TIMER: // Normal case: timer expired, we should just go back to sleep ASAP - setLed(true); // briefly turn on led + ledBlink.set(true); // briefly turn on led wakeCause2 = doLightSleep(100); // leave led on for 1ms secsSlept += sleepTime; @@ -134,7 +133,7 @@ static void lsIdle() } } else { // Time to stop sleeping! - setLed(false); + ledBlink.set(false); LOG_INFO("Reached ls_secs, servicing loop()\n"); powerFSM.trigger(EVENT_WAKE_TIMER); } @@ -149,7 +148,6 @@ static void lsExit() static void nbEnter() { LOG_DEBUG("Enter state: NB\n"); - powerMon->clearState(meshtastic_PowerMon_State_BT_On); screen->setOn(false); #ifdef ARCH_ESP32 // Only ESP32 should turn off bluetooth @@ -161,8 +159,6 @@ static void nbEnter() static void darkEnter() { - powerMon->clearState(meshtastic_PowerMon_State_BT_On); - powerMon->clearState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(true); screen->setOn(false); } @@ -170,8 +166,6 @@ static void darkEnter() static void serialEnter() { LOG_DEBUG("Enter state: SERIAL\n"); - powerMon->clearState(meshtastic_PowerMon_State_BT_On); - powerMon->setState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(false); screen->setOn(true); screen->print("Serial connected\n"); @@ -180,7 +174,6 @@ static void serialEnter() static void serialExit() { // Turn bluetooth back on when we leave serial stream API - powerMon->setState(meshtastic_PowerMon_State_BT_On); setBluetoothEnable(true); screen->print("Serial disconnected\n"); } @@ -193,8 +186,6 @@ static void powerEnter() LOG_INFO("Loss of power in Powered\n"); powerFSM.trigger(EVENT_POWER_DISCONNECTED); } else { - powerMon->setState(meshtastic_PowerMon_State_BT_On); - powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); // within enter() the function getState() returns the state we came from @@ -218,8 +209,6 @@ static void powerIdle() static void powerExit() { - powerMon->setState(meshtastic_PowerMon_State_BT_On); - powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); @@ -231,8 +220,6 @@ static void powerExit() static void onEnter() { LOG_DEBUG("Enter state: ON\n"); - powerMon->setState(meshtastic_PowerMon_State_BT_On); - powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); } diff --git a/src/PowerMon.cpp b/src/PowerMon.cpp index 3d28715e0..16909262d 100644 --- a/src/PowerMon.cpp +++ b/src/PowerMon.cpp @@ -2,9 +2,11 @@ #include "NodeDB.h" // Use the 'live' config flag to figure out if we should be showing this message -static bool is_power_enabled(uint64_t m) +bool PowerMon::is_power_enabled(uint64_t m) { - return (m & config.power.powermon_enables) ? true : false; + // FIXME: VERY STRANGE BUG: if I or in "force_enabled || " the flashed image on a rak4631 is not accepted by the bootloader as + // valid!!! Possibly a linker/gcc/bootloader bug somewhere? + return ((m & config.power.powermon_enables) ? true : false); } void PowerMon::setState(_meshtastic_PowerMon_State state, const char *reason) diff --git a/src/PowerMon.h b/src/PowerMon.h index e9f5dbd59..a19a6d010 100644 --- a/src/PowerMon.h +++ b/src/PowerMon.h @@ -17,6 +17,13 @@ class PowerMon { uint64_t states = 0UL; + friend class PowerStressModule; + + /** + * If stress testing we always want all events logged + */ + bool force_enabled = false; + public: PowerMon() {} @@ -27,6 +34,9 @@ class PowerMon private: // Emit the coded log message void emitLog(const char *reason); + + // Use the 'live' config flag to figure out if we should be showing this message + bool is_power_enabled(uint64_t m); }; extern PowerMon *powerMon; diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 633fb4c67..fe6fd3f06 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -21,6 +21,7 @@ along with this program. If not, see . */ #include "Screen.h" #include "../userPrefs.h" +#include "PowerMon.h" #include "configuration.h" #if HAS_SCREEN #include @@ -1574,6 +1575,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) if (on != screenOn) { if (on) { LOG_INFO("Turning on screen\n"); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); #ifdef T_WATCH_S3 PMU->enablePowerOutput(XPOWERS_ALDO2); #endif @@ -1599,6 +1601,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) setInterval(0); // Draw ASAP runASAP = true; } else { + powerMon->clearState(meshtastic_PowerMon_State_Screen_On); #ifdef USE_EINK // eInkScreensaver parameter is usually NULL (default argument), default frame used instead setScreensaverFrames(einkScreensaver); diff --git a/src/main.cpp b/src/main.cpp index 64fe04f00..f4f7ad537 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,7 @@ #include "power.h" // #include "debug.h" #include "FSCommon.h" +#include "Led.h" #include "RTC.h" #include "SPILock.h" #include "concurrency/OSThread.h" @@ -197,7 +198,7 @@ static int32_t ledBlinker() static bool ledOn; ledOn ^= 1; - setLed(ledOn); + ledBlink.set(ledOn); // have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000); diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index ca2c5d4be..9a981ee54 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -9,9 +9,9 @@ #if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif +#include "Led.h" #include "power.h" #include "serialization/JSON.h" -#include "sleep.h" #include #include #include @@ -798,9 +798,9 @@ void handleBlinkLED(HTTPRequest *req, HTTPResponse *res) if (blink_target == "LED") { uint8_t count = 10; while (count > 0) { - setLed(true); + ledBlink.set(true); delay(50); - setLed(false); + ledBlink.set(false); delay(50); count = count - 1; } diff --git a/src/modules/PowerStressModule.cpp b/src/modules/PowerStressModule.cpp index c86017ae2..4c9f0df88 100644 --- a/src/modules/PowerStressModule.cpp +++ b/src/modules/PowerStressModule.cpp @@ -1,10 +1,14 @@ #include "PowerStressModule.h" +#include "Led.h" #include "MeshService.h" #include "NodeDB.h" +#include "PowerMon.h" #include "RTC.h" #include "Router.h" #include "configuration.h" #include "main.h" +#include "sleep.h" +#include "target_specific.h" extern void printInfo(); @@ -29,6 +33,10 @@ bool PowerStressModule::handleReceivedProtobuf(const meshtastic_MeshPacket &req, case meshtastic_PowerStressMessage_Opcode_PRINT_INFO: printInfo(); + + // Now that we know we are actually doing power stress testing, go ahead and turn on all enables (so the log is fully + // detailed) + powerMon->force_enabled = true; break; default: @@ -44,7 +52,6 @@ bool PowerStressModule::handleReceivedProtobuf(const meshtastic_MeshPacket &req, int32_t PowerStressModule::runOnce() { - if (!config.power.powermon_enables) { // Powermon not enabled - stop using CPU/stop this thread return disable(); @@ -58,19 +65,68 @@ int32_t PowerStressModule::runOnce() // Done with the previous command - our sleep must have finished p.cmd = meshtastic_PowerStressMessage_Opcode_UNSET; p.num_seconds = 0; + isRunningCommand = false; + LOG_INFO("S:PS:%u\n", p.cmd); } else { - sleep_msec = (int32_t)(p.num_seconds * 1000); - isRunningCommand = !!sleep_msec; // if the command wants us to sleep, make sure to mark that we have something running + if (p.cmd != meshtastic_PowerStressMessage_Opcode_UNSET) { + sleep_msec = (int32_t)(p.num_seconds * 1000); + isRunningCommand = !!sleep_msec; // if the command wants us to sleep, make sure to mark that we have something running + LOG_INFO( + "S:PS:%u\n", + p.cmd); // Emit a structured log saying we are starting a powerstress state (to make it easier to parse later) - switch (p.cmd) { - case meshtastic_PowerStressMessage_Opcode_UNSET: // No need to start a new command - break; - case meshtastic_PowerStressMessage_Opcode_LED_ON: - break; - default: - LOG_ERROR("PowerStress operation %d not yet implemented!\n", p.cmd); - sleep_msec = 0; // Don't do whatever sleep was requested... - break; + switch (p.cmd) { + case meshtastic_PowerStressMessage_Opcode_LED_ON: + ledForceOn.set(true); + break; + case meshtastic_PowerStressMessage_Opcode_LED_OFF: + ledForceOn.set(false); + break; + case meshtastic_PowerStressMessage_Opcode_GPS_ON: + // FIXME - implement + break; + case meshtastic_PowerStressMessage_Opcode_GPS_OFF: + // FIXME - implement + break; + case meshtastic_PowerStressMessage_Opcode_LORA_OFF: + // FIXME - implement + break; + case meshtastic_PowerStressMessage_Opcode_LORA_RX: + // FIXME - implement + break; + case meshtastic_PowerStressMessage_Opcode_LORA_TX: + // FIXME - implement + break; + case meshtastic_PowerStressMessage_Opcode_SCREEN_OFF: + // FIXME - implement + break; + case meshtastic_PowerStressMessage_Opcode_SCREEN_ON: + // FIXME - implement + break; + case meshtastic_PowerStressMessage_Opcode_BT_OFF: + setBluetoothEnable(false); + break; + case meshtastic_PowerStressMessage_Opcode_BT_ON: + setBluetoothEnable(true); + break; + case meshtastic_PowerStressMessage_Opcode_CPU_DEEPSLEEP: + doDeepSleep(sleep_msec, true); + break; + case meshtastic_PowerStressMessage_Opcode_CPU_FULLON: { + uint32_t start_msec = millis(); + while ((millis() - start_msec) < (uint32_t)sleep_msec) + ; // Don't let CPU idle at all + sleep_msec = 0; // we already slept + break; + } + case meshtastic_PowerStressMessage_Opcode_CPU_IDLE: + // FIXME - implement + break; + default: + LOG_ERROR("PowerStress operation %d not yet implemented!\n", p.cmd); + sleep_msec = 0; // Don't do whatever sleep was requested... + break; + } } } return sleep_msec; diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 6bce498ab..19f435908 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -1,4 +1,5 @@ #include "PowerFSM.h" +#include "PowerMon.h" #include "configuration.h" #include "esp_task_wdt.h" #include "main.h" @@ -34,6 +35,7 @@ void setBluetoothEnable(bool enable) nimbleBluetooth = new NimbleBluetooth(); } if (enable && !nimbleBluetooth->isActive()) { + powerMon->setState(meshtastic_PowerMon_State_BT_On); nimbleBluetooth->setup(); } // For ESP32, no way to recover from bluetooth shutdown without reboot diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 7334f3a04..a7d5d8c3d 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -9,6 +9,7 @@ #include // #include #include "NodeDB.h" +#include "PowerMon.h" #include "error.h" #include "main.h" @@ -91,6 +92,8 @@ void setBluetoothEnable(bool enable) } if (enable) { + powerMon->setState(meshtastic_PowerMon_State_BT_On); + // If not yet set-up if (!nrf52Bluetooth) { LOG_DEBUG("Initializing NRF52 Bluetooth\n"); @@ -105,8 +108,10 @@ void setBluetoothEnable(bool enable) nrf52Bluetooth->resumeAdvertising(); } // Disable (if previously set-up) - else if (nrf52Bluetooth) + else if (nrf52Bluetooth) { + powerMon->clearState(meshtastic_PowerMon_State_BT_On); nrf52Bluetooth->shutdown(); + } } #else #warning NRF52 "Bluetooth disable" workaround does not apply to builds with MESHTASTIC_EXCLUDE_BLUETOOTH diff --git a/src/power.h b/src/power.h index b970dfeaf..a4307ee07 100644 --- a/src/power.h +++ b/src/power.h @@ -53,6 +53,13 @@ extern INA3221Sensor ina3221Sensor; extern RAK9154Sensor rak9154Sensor; #endif +#ifdef HAS_PMU +#include "XPowersAXP192.tpp" +#include "XPowersAXP2101.tpp" +#include "XPowersLibInterface.hpp" +extern XPowersLibInterface *PMU; +#endif + class Power : private concurrency::OSThread { diff --git a/src/sleep.cpp b/src/sleep.cpp index 486d22dfe..b4171002a 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -5,6 +5,7 @@ #endif #include "ButtonThread.h" +#include "Led.h" #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" @@ -81,26 +82,6 @@ void setCPUFast(bool on) #endif } -void setLed(bool ledOn) -{ - if (ledOn) - powerMon->setState(meshtastic_PowerMon_State_LED_On); - else - powerMon->clearState(meshtastic_PowerMon_State_LED_On); - -#ifdef LED_PIN - // toggle the led so we can get some rough sense of how often loop is pausing - digitalWrite(LED_PIN, ledOn ^ LED_STATE_ON ^ HIGH); -#endif - -#ifdef HAS_PMU - if (pmu_found && PMU) { - // blink the axp led - PMU->setChargingLedMode(ledOn ? XPOWERS_CHG_LED_ON : XPOWERS_CHG_LED_OFF); - } -#endif -} - // Perform power on init that we do on each wake from deep sleep void initDeepSleep() { @@ -230,6 +211,8 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) notifyDeepSleep.notifyObservers(NULL); #endif + powerMon->setState(meshtastic_PowerMon_State_CPU_DeepSleep); + screen->doDeepSleep(); // datasheet says this will draw only 10ua nodeDB->saveToDisk(); @@ -257,7 +240,7 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) digitalWrite(PIN_3V3_EN, LOW); #endif #endif - setLed(false); + ledBlink.set(false); #ifdef RESET_OLED digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power diff --git a/src/sleep.h b/src/sleep.h index f154b8d44..6ac420769 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -22,7 +22,6 @@ extern XPowersLibInterface *PMU; void initDeepSleep(); void setCPUFast(bool on); -void setLed(bool ledOn); /** return true if sleep is allowed right now */ bool doPreflightSleep(); diff --git a/variants/tbeam-s3-core/pins_arduino.h b/variants/tbeam-s3-core/pins_arduino.h index 24edb7d9f..e66b69e02 100644 --- a/variants/tbeam-s3-core/pins_arduino.h +++ b/variants/tbeam-s3-core/pins_arduino.h @@ -6,13 +6,13 @@ #define USB_VID 0x303a #define USB_PID 0x1001 -#define EXTERNAL_NUM_INTERRUPTS 46 -#define NUM_DIGITAL_PINS 48 -#define NUM_ANALOG_INPUTS 20 - -#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1) -#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1) -#define digitalPinHasPWM(p) (p < 46) +// Now declared in .platformio/packages/framework-arduinoespressif32/cores/esp32/Arduino.h +// #define NUM_ANALOG_INPUTS 20 +// #define EXTERNAL_NUM_INTERRUPTS 46 +// #define NUM_DIGITAL_PINS 48 +// #define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1) +// #define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1) +// #define digitalPinHasPWM(p) (p < 46) static const uint8_t TX = 43; static const uint8_t RX = 44; @@ -39,4 +39,4 @@ static const uint8_t SCK = 12; // #define PMU_IRQ (40) #define RTC_INT (14) -#endif /* Pins_Arduino_h */ +#endif /* Pins_Arduino_h */ \ No newline at end of file