mirror of
https://github.com/meshtastic/firmware.git
synced 2026-10-09 14:41:19 -04:00
* fix(power): stop a battery-less board deep-sleeping itself forever The low-battery counter only reset inside its `hasBattery && !hasUSB` guard, so a board with no battery - whose floating divider drifts in and out of the battery-present window - ratcheted the count up across the gaps until it tripped `sds_secs`, which defaults to a ~24.8-day deep sleep. The button could not rescue it either, because `doDeepSleep()` force-holds `BUTTON_PIN` and a held pad ignores `ext1_wakeup_prepare()`'s re-route to RTC; `rtc_gpio_isolate()`'s pin list has the same effect on boards whose button is GPIO 2 or 34. Separately the cutoff now scales by `NUM_CELLS`, without which no multi-cell pack can ever read low enough to shut down at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(power): satisfy trunk check Apply the `ascii-dash` autoformat that `trunk fmt` wants on the comments this PR's file already carries, and rename the no-battery test so its `test_` prefix plus exactly 35 characters stops matching trufflehog's Lob API-key shape. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
166 lines
4.6 KiB
C++
166 lines
4.6 KiB
C++
#pragma once
|
|
#include "PowerStatus.h"
|
|
#include "concurrency/OSThread.h"
|
|
#include "configuration.h"
|
|
|
|
#ifdef ARCH_ESP32
|
|
// #include <driver/adc.h>
|
|
#include <esp_adc/adc_cali.h>
|
|
#include <esp_adc/adc_cali_scheme.h>
|
|
#include <esp_adc/adc_oneshot.h>
|
|
#include <soc/adc_channel.h>
|
|
#endif
|
|
|
|
#ifndef NUM_OCV_POINTS
|
|
#define NUM_OCV_POINTS 11
|
|
#endif
|
|
|
|
// Device specific curves go in variant.h
|
|
#ifndef OCV_ARRAY
|
|
#if defined(ARCH_STM32) && BATTERY_PIN == AVBAT
|
|
// STM32 VDD/VBAT absolute maximum is 4V so use an LFP curve
|
|
#define OCV_ARRAY 3650, 3400, 3340, 3320, 3300, 3280, 3270, 3260, 3240, 3200, 2500
|
|
#else
|
|
#define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100
|
|
#endif
|
|
#endif
|
|
|
|
/*Note: 12V lead acid is 6 cells, most board accept only 1 cell LiIon/LiPo*/
|
|
#ifndef NUM_CELLS
|
|
#define NUM_CELLS 1
|
|
#endif
|
|
|
|
/// Consecutive below-cutoff readings needed before the low-battery deep sleep fires.
|
|
static constexpr uint8_t LOW_VOLTAGE_READINGS_BEFORE_SHUTDOWN = 10;
|
|
|
|
/// Advance the low-battery shutdown counter by one reading; true once the device should deep sleep.
|
|
bool updateLowVoltageCounter(uint8_t &counter, bool hasBattery, bool hasUsb, uint16_t battMv, uint16_t cutoffMv);
|
|
|
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
|
#include "modules/Telemetry/Sensor/nullSensor.h"
|
|
#if __has_include(<Adafruit_INA219.h>)
|
|
#include "modules/Telemetry/Sensor/INA219Sensor.h"
|
|
extern INA219Sensor ina219Sensor;
|
|
#else
|
|
extern NullSensor ina219Sensor;
|
|
#endif
|
|
|
|
#if __has_include(<INA226.h>)
|
|
#include "modules/Telemetry/Sensor/INA226Sensor.h"
|
|
extern INA226Sensor ina226Sensor;
|
|
#else
|
|
extern NullSensor ina226Sensor;
|
|
#endif
|
|
|
|
#if __has_include(<Adafruit_INA260.h>)
|
|
#include "modules/Telemetry/Sensor/INA260Sensor.h"
|
|
extern INA260Sensor ina260Sensor;
|
|
#else
|
|
extern NullSensor ina260Sensor;
|
|
#endif
|
|
|
|
#if __has_include(<INA3221.h>)
|
|
#include "modules/Telemetry/Sensor/INA3221Sensor.h"
|
|
extern INA3221Sensor ina3221Sensor;
|
|
#else
|
|
extern NullSensor ina3221Sensor;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
|
#if __has_include(<Adafruit_MAX1704X.h>)
|
|
#include "modules/Telemetry/Sensor/MAX17048Sensor.h"
|
|
extern MAX17048Sensor max17048Sensor;
|
|
#else
|
|
extern NullSensor max17048Sensor;
|
|
#endif
|
|
#endif
|
|
|
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && HAS_RAKPROT
|
|
#include "modules/Telemetry/Sensor/RAK9154Sensor.h"
|
|
extern RAK9154Sensor rak9154Sensor;
|
|
#endif
|
|
|
|
#ifdef HAS_PMU
|
|
#include "XPowersAXP192.tpp"
|
|
#include "XPowersAXP2101.tpp"
|
|
#include "XPowersLibInterface.hpp"
|
|
extern XPowersLibInterface *PMU;
|
|
#endif
|
|
|
|
class Power : public concurrency::OSThread
|
|
{
|
|
|
|
public:
|
|
Observable<const meshtastic::PowerStatus *> newStatus;
|
|
|
|
Power();
|
|
|
|
void powerCommandsCheck();
|
|
void readPowerStatus();
|
|
void logHeapUsage();
|
|
virtual bool setup();
|
|
virtual int32_t runOnce() override;
|
|
void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; }
|
|
const uint16_t OCV[11] = {OCV_ARRAY};
|
|
bool isLowBattery() { return low_voltage_counter >= LOW_VOLTAGE_READINGS_BEFORE_SHUTDOWN; };
|
|
|
|
#ifdef ARCH_ESP32
|
|
int beforeLightSleep(void *unused);
|
|
int afterLightSleep(esp_sleep_wakeup_cause_t cause);
|
|
#endif
|
|
|
|
void attachPowerInterrupts();
|
|
void detachPowerInterrupts();
|
|
|
|
protected:
|
|
meshtastic::PowerStatus *statusHandler;
|
|
|
|
/// Setup a xpowers chip axp192/axp2101, return true if found
|
|
bool axpChipInit();
|
|
/// Setup a simple ADC input based battery sensor
|
|
bool analogInit();
|
|
/// Setup cw2015 battery level sensor
|
|
bool cw2015Init();
|
|
/// Setup a 17048 battery level sensor
|
|
bool max17048Init();
|
|
/// Setup a Lipo charger
|
|
bool lipoChargerInit();
|
|
/// Retry a fuel gauge that did not come up during setup
|
|
void lipoChargerRetry();
|
|
/// Setup a meshSolar battery sensor
|
|
bool meshSolarInit();
|
|
/// Setup a serial battery sensor
|
|
bool serialBatteryInit();
|
|
#ifdef HAS_ADS1115
|
|
/// Setup ADS1115 I2C battery level sensor
|
|
bool ads1115Init();
|
|
#endif
|
|
|
|
private:
|
|
void shutdown();
|
|
void reboot();
|
|
// open circuit voltage lookup table
|
|
uint8_t low_voltage_counter;
|
|
uint32_t lastLogTime = 0;
|
|
// Periodic free-heap logging: time of the last line emitted, and the reading it carried
|
|
uint32_t lastHeapLogTime = 0;
|
|
uint32_t lastHeapLogFree = 0;
|
|
|
|
#ifdef ARCH_ESP32
|
|
// Get notified when lightsleep begins and ends
|
|
CallbackObserver<Power, void *> lsObserver = CallbackObserver<Power, void *>(this, &Power::beforeLightSleep);
|
|
CallbackObserver<Power, esp_sleep_wakeup_cause_t> lsEndObserver =
|
|
CallbackObserver<Power, esp_sleep_wakeup_cause_t>(this, &Power::afterLightSleep);
|
|
#endif
|
|
|
|
#ifdef DEBUG_HEAP
|
|
uint32_t lastheap;
|
|
#endif
|
|
};
|
|
|
|
void battery_adcEnable();
|
|
|
|
extern Power *power;
|