mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-13 15:11:20 +10:00
* fix(Power): survive a BQ27220 fuel gauge that fails to init Keep the BQ25896 as the battery source when only the gauge fails, so Power stays enabled instead of falling through to an ADC that these variants do not have. Null-guard the gauge in getBattVoltage() and isCharging(). Retry the gauge from the power thread (3 attempts, 60s apart, address probe first) since it is soldered on, and reset the I2C master after a failed init so the bus scan does not run against a stale transaction. Fixes #11372 * fix(Power): address review feedback on the BQ27220 retry Derive "no attempt yet" from gaugeAttemptsLeft instead of a millis() zero sentinel, drop the zero-padding on the logged I2C address, and condense the new comment blocks.
156 lines
4.2 KiB
C++
156 lines
4.2 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
|
|
|
|
#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 >= 10; };
|
|
|
|
#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();
|
|
|
|
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;
|