LoRa_APRS_Tracker111/src/power_utils.cpp

502 lines
17 KiB
C++

#include <SPI.h>
#include "notification_utils.h"
#include "configuration.h"
#include "boards_pinout.h"
#include "power_utils.h"
#include "lora_utils.h"
#include "ble_utils.h"
#include "gps_utils.h"
#include "display.h"
#include "logger.h"
#if !defined(TTGO_T_Beam_S3_SUPREME_V3) && !defined(HELTEC_WIRELESS_TRACKER)
#define I2C_SDA 21
#define I2C_SCL 22
#define IRQ_PIN 35
#endif
#ifdef TTGO_T_Beam_S3_SUPREME_V3
#define I2C0_SDA 17
#define I2C0_SCL 18
#define I2C1_SDA 42
#define I2C1_SCL 41
#define IRQ_PIN 40
#endif
#ifdef HAS_AXP192
XPowersAXP192 PMU;
#endif
#ifdef HAS_AXP2101
XPowersAXP2101 PMU;
#endif
extern Configuration Config;
extern logging::Logger logger;
extern bool transmitFlag;
extern bool gpsIsActive;
uint32_t batteryMeasurmentTime = 0;
bool pmuInterrupt;
float lora32BatReadingCorr = 6.5; // % of correction to higher value to reflect the real battery voltage (adjust this to your needs)
bool disableGPS;
namespace POWER_Utils {
bool BatteryIsConnected = false;
String batteryVoltage = "";
String batteryChargeDischargeCurrent = "";
double getBatteryVoltage() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
return (PMU.getBattVoltage() / 1000.0);
#else
#ifdef BATTERY_PIN
#ifdef ADC_CTRL
#ifdef HELTEC_WIRELESS_TRACKER
digitalWrite(ADC_CTRL, HIGH);
#endif
#if defined(HELTEC_V3_GPS) || defined(HELTEC_V3_TNC)|| defined(HELTEC_V2_GPS) || defined(HELTEC_V2_GPS_915)
digitalWrite(ADC_CTRL, LOW);
#endif
#endif
int adc_value = analogRead(BATTERY_PIN);
#ifdef ADC_CTRL
#ifdef HELTEC_WIRELESS_TRACKER
digitalWrite(ADC_CTRL, LOW);
#endif
#if defined(HELTEC_V3_GPS) || defined(HELTEC_V3_TNC) || defined(HELTEC_V2_GPS) || defined(HELTEC_V2_GPS_915)
digitalWrite(ADC_CTRL, HIGH);
#endif
batteryMeasurmentTime = millis();
#endif
double voltage = (adc_value * 3.3 ) / 4095.0;
#if defined(TTGO_T_Beam_V0_7) || defined(TTGO_T_LORA32_V2_1_GPS) || defined(TTGO_T_LORA32_V2_1_GPS_915) || defined(TTGO_T_LORA32_V2_1_TNC) || defined(TTGO_T_LORA32_V2_1_TNC_915) || defined(ESP32_DIY_LoRa_GPS) || defined(ESP32_DIY_LoRa_GPS_915) || defined(ESP32_DIY_1W_LoRa_GPS) || defined(ESP32_DIY_1W_LoRa_GPS_915) || defined(ESP32_DIY_1W_LoRa_GPS_LLCC68) || defined(OE5HWN_MeshCom) || defined(TTGO_T_DECK_GPS) || defined(ESP32S3_DIY_LoRa_GPS) || defined(ESP32S3_DIY_LoRa_GPS_915)
return (2 * (voltage + 0.1)) * (1 + (lora32BatReadingCorr/100)); // (2 x 100k voltage divider) 2 x voltage divider/+0.1 because ESP32 nonlinearity ~100mV ADC offset/extra correction
#endif
#if defined(HELTEC_V3_GPS) || defined(HELTEC_V3_TNC)|| defined(HELTEC_WIRELESS_TRACKER) || defined(ESP32_C3_DIY_LoRa_GPS) || defined(ESP32_C3_DIY_LoRa_GPS_915) || defined(WEMOS_ESP32_Bat_LoRa_GPS)
double inputDivider = (1.0 / (390.0 + 100.0)) * 100.0; // The voltage divider is a 390k + 100k resistor in series, 100k on the low side.
return (voltage / inputDivider) + 0.285; // Yes, this offset is excessive, but the ADC on the ESP32s3 is quite inaccurate and noisy. Adjust to own measurements.
#endif
#if defined(HELTEC_V2_GPS) || defined(HELTEC_V2_GPS_915)
double inputDivider = (1.0 / (220.0 + 100.0)) * 100.0; // The voltage divider is a 390k + 100k resistor in series, 100k on the low side.
return (voltage / inputDivider) + 0.285; // Yes, this offset is excessive, but the ADC on the ESP32s3 is quite inaccurate and noisy. Adjust to own measurements.
#endif
#else
return 0.0;
#endif
#endif
}
const String getBatteryInfoVoltage() {
return batteryVoltage;
}
const String getBatteryInfoCurrent() {
return batteryChargeDischargeCurrent;
}
bool getBatteryInfoIsConnected() {
return BatteryIsConnected;
}
void enableChgLed() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
PMU.setChargingLedMode(XPOWERS_CHG_LED_ON);
#endif
}
void disableChgLed() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
PMU.setChargingLedMode(XPOWERS_CHG_LED_OFF);
#endif
}
bool isCharging() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
return PMU.isCharging();
#else
return 0;
#endif
}
void handleChargingLed() {
if (isCharging()) {
enableChgLed();
} else {
disableChgLed();
}
}
double getBatteryChargeDischargeCurrent() {
#if !defined(HAS_AXP192) && !defined(HAS_AXP2101)
return 0;
#endif
#ifdef HAS_AXP192
if (PMU.isCharging()) {
return PMU.getBatteryChargeCurrent();
}
return -1.0 * PMU.getBattDischargeCurrent();
#endif
#ifdef HAS_AXP2101
return PMU.getBatteryPercent();
#endif
}
bool isBatteryConnected() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
return PMU.isBatteryConnect();
#else
if(getBatteryVoltage() > 1.0) {
return true;
} else {
return false;
}
#endif
}
void obtainBatteryInfo() {
static unsigned int rate_limit_check_battery = 0;
if (!(rate_limit_check_battery++ % 60))
BatteryIsConnected = isBatteryConnected();
if (BatteryIsConnected) {
#ifdef HAS_AXP2101
batteryVoltage = String(PMU.getBattVoltage()/1000);
#else
batteryVoltage = String(getBatteryVoltage(), 2);
#endif
batteryChargeDischargeCurrent = String(getBatteryChargeDischargeCurrent(), 0);
}
}
void batteryManager() {
#ifdef ADC_CTRL
if(batteryMeasurmentTime == 0 || (millis() - batteryMeasurmentTime) > 30 * 1000) obtainBatteryInfo();
#else
obtainBatteryInfo();
#endif
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
handleChargingLed();
#endif
}
void activateMeasurement() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
PMU.disableTSPinMeasure();
PMU.enableBattDetection();
PMU.enableVbusVoltageMeasure();
PMU.enableBattVoltageMeasure();
PMU.enableSystemVoltageMeasure();
#endif
}
void activateGPS() {
#ifdef HAS_AXP192
PMU.setLDO3Voltage(3300);
PMU.enableLDO3();
#endif
#ifdef HAS_AXP2101
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.setALDO4Voltage(3300);
PMU.enableALDO4();
#else
PMU.setALDO3Voltage(3300);
PMU.enableALDO3();
#endif
#endif
#ifdef HELTEC_WIRELESS_TRACKER
digitalWrite(VEXT_CTRL, HIGH);
#endif
gpsIsActive = true;
}
void deactivateGPS() {
#ifdef HAS_AXP192
PMU.disableLDO3();
#endif
#ifdef HAS_AXP2101
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.disableALDO4();
#else
PMU.disableALDO3();
#endif
#endif
#ifdef HELTEC_WIRELESS_TRACKER
digitalWrite(VEXT_CTRL, LOW);
#endif
gpsIsActive = false;
}
void activateLoRa() {
#ifdef HAS_AXP192
PMU.setLDO2Voltage(3300);
PMU.enableLDO2();
#endif
#ifdef HAS_AXP2101
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.setALDO3Voltage(3300);
PMU.enableALDO3();
#else
PMU.setALDO2Voltage(3300);
PMU.enableALDO2();
#endif
#endif
}
void deactivateLoRa() {
#ifdef HAS_AXP192
PMU.disableLDO2();
#endif
#ifdef HAS_AXP2101
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.disableALDO3();
#else
PMU.disableALDO2();
#endif
#endif
}
void externalPinSetup() {
if (Config.notification.buzzerActive && Config.notification.buzzerPinTone >= 0 && Config.notification.buzzerPinVcc >= 0) {
pinMode(Config.notification.buzzerPinTone, OUTPUT);
pinMode(Config.notification.buzzerPinVcc, OUTPUT);
if (Config.notification.bootUpBeep) NOTIFICATION_Utils::start();
} else if (Config.notification.buzzerActive && (Config.notification.buzzerPinTone < 0 || Config.notification.buzzerPinVcc < 0)) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "PINOUT", "Buzzer Pins not defined");
while (1);
}
if (Config.notification.ledTx && Config.notification.ledTxPin >= 0) {
pinMode(Config.notification.ledTxPin, OUTPUT);
} else if (Config.notification.ledTx && Config.notification.ledTxPin < 0) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "PINOUT", "Led Tx Pin not defined");
while (1);
}
if (Config.notification.ledMessage && Config.notification.ledMessagePin >= 0) {
pinMode(Config.notification.ledMessagePin, OUTPUT);
} else if (Config.notification.ledMessage && Config.notification.ledMessagePin < 0) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "PINOUT", "Led Message Pin not defined");
while (1);
}
if (Config.notification.ledFlashlight && Config.notification.ledFlashlightPin >= 0) {
pinMode(Config.notification.ledFlashlightPin, OUTPUT);
} else if (Config.notification.ledFlashlight && Config.notification.ledFlashlightPin < 0) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "PINOUT", "Led Flashlight Pin not defined");
while (1);
}
if (Config.ptt.active && Config.ptt.io_pin >= 0) {
pinMode(Config.ptt.io_pin, OUTPUT);
digitalWrite(Config.ptt.io_pin, Config.ptt.reverse ? HIGH : LOW);
} else if (Config.ptt.active && Config.ptt.io_pin < 0) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "PINOUT", "PTT Pin not defined");
while (1);
}
}
bool begin(TwoWire &port) {
#if !defined(HAS_AXP192) && !defined(HAS_AXP2101)
return true; // no powerManagment chip for this boards (only a few measure battery voltage).
#endif
#ifdef HAS_AXP192
bool result = PMU.begin(Wire, AXP192_SLAVE_ADDRESS, I2C_SDA, I2C_SCL);
if (result) {
PMU.disableDC2();
PMU.disableLDO2();
PMU.disableLDO3();
PMU.setDC1Voltage(3300);
PMU.enableDC1();
PMU.setProtectedChannel(XPOWERS_DCDC3);
PMU.disableIRQ(XPOWERS_AXP192_ALL_IRQ);
}
return result;
#endif
#ifdef HAS_AXP2101
#ifdef TTGO_T_Beam_S3_SUPREME_V3
bool result = PMU.begin(Wire1, AXP2101_SLAVE_ADDRESS, I2C1_SDA, I2C1_SCL);
#else
bool result = PMU.begin(Wire, AXP2101_SLAVE_ADDRESS, I2C_SDA, I2C_SCL);
#endif
if (result) {
PMU.disableDC2();
PMU.disableDC3();
PMU.disableDC4();
PMU.disableDC5();
#ifndef TTGO_T_Beam_S3_SUPREME_V3
PMU.disableALDO1();
PMU.disableALDO4();
#endif
PMU.disableBLDO1();
PMU.disableBLDO2();
PMU.disableDLDO1();
PMU.disableDLDO2();
PMU.setDC1Voltage(3300);
PMU.enableDC1();
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.setALDO1Voltage(3300);
#endif
PMU.setButtonBatteryChargeVoltage(3300);
PMU.enableButtonBatteryCharge();
PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
}
return result;
#endif
}
void setup() {
#ifdef HAS_NO_GPS
disableGPS = true;
#else
disableGPS = Config.disableGPS;
#endif
#ifdef HAS_AXP192
Wire.begin(SDA, SCL);
if (begin(Wire)) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "AXP192", "init done!");
} else {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "AXP192", "init failed!");
}
activateLoRa();
if (disableGPS) {
deactivateGPS();
} else {
activateGPS();
}
activateMeasurement();
PMU.setChargerTerminationCurr(XPOWERS_AXP192_CHG_ITERM_LESS_10_PERCENT);
PMU.setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
PMU.setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_780MA);
PMU.setSysPowerDownVoltage(2600);
#endif
#ifdef HAS_AXP2101
bool beginStatus = false;
#ifdef TTGO_T_Beam_S3_SUPREME_V3
Wire1.begin(I2C1_SDA, I2C1_SCL);
Wire.begin(I2C0_SDA, I2C0_SCL);
if (begin(Wire1)) beginStatus = true;
#else
Wire.begin(SDA, SCL);
if (begin(Wire)) beginStatus = true;
#endif
if (beginStatus) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "AXP2101", "init done!");
} else {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "AXP2101", "init failed!");
}
activateLoRa();
if (disableGPS) {
deactivateGPS();
} else {
activateGPS();
}
activateMeasurement();
PMU.setPrechargeCurr(XPOWERS_AXP2101_PRECHARGE_200MA);
PMU.setChargerTerminationCurr(XPOWERS_AXP2101_CHG_ITERM_25MA);
PMU.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
PMU.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_800MA);
PMU.setSysPowerDownVoltage(2600);
#endif
#ifdef BATTERY_PIN
pinMode(BATTERY_PIN, INPUT);
#endif
#ifdef VEXT_CTRL
pinMode(VEXT_CTRL,OUTPUT); // this is for GPS and TFT screen on Wireless_Tracker and only for Oled in Heltec V3
digitalWrite(VEXT_CTRL, HIGH);
#endif
#ifdef ADC_CTRL
pinMode(ADC_CTRL, OUTPUT);
#endif
#ifdef HELTEC_WIRELESS_TRACKER
Wire.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
#if defined(HELTEC_V3_GPS) || defined(HELTEC_V3_TNC)
Wire1.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
#if defined(TTGO_T_DECK_GPS)
pinMode(BOARD_POWERON, OUTPUT);
digitalWrite(BOARD_POWERON, HIGH);
pinMode(BOARD_SDCARD_CS, OUTPUT);
pinMode(RADIO_CS_PIN, OUTPUT);
pinMode(TFT_CS, OUTPUT);
digitalWrite(BOARD_SDCARD_CS, HIGH);
digitalWrite(RADIO_CS_PIN, HIGH);
digitalWrite(TFT_CS, HIGH);
pinMode(TrackBallCenter, INPUT_PULLUP);
pinMode(TrackBallUp, INPUT_PULLUP);
pinMode(TrackBallDown, INPUT_PULLUP);
pinMode(TrackBallLeft, INPUT_PULLUP);
pinMode(TrackBallRight, INPUT_PULLUP);
delay(500);
Wire.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
}
void lowerCpuFrequency() {
if (setCpuFrequencyMhz(80)) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, "Main", "CPU frequency set to 80MHz");
} else {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "Main", "CPU frequency unchanged");
}
}
void shutdown() {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "Main", "SHUTDOWN !!!");
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
if (Config.notification.shutDownBeep) NOTIFICATION_Utils::shutDownBeep();
displayToggle(false);
PMU.shutdown();
#else
if (Config.bluetoothType == 0 || Config.bluetoothType == 2) {
BLE_Utils::stop();
} else {
// turn off BT classic ???
}
#ifdef VEXT_CTRL
digitalWrite(VEXT_CTRL, LOW);
#endif
#ifdef ADC_CTRL
#ifdef HELTEC_WIRELESS_TRACKER
digitalWrite(ADC_CTRL, LOW);
#endif
#if defined(HELTEC_V3_GPS) || defined(HELTEC_V3_TNC)
digitalWrite(ADC_CTRL, HIGH);
#endif
#endif
LoRa_Utils::sleepRadio();
long DEEP_SLEEP_TIME_SEC = 1296000; // 15 days
esp_sleep_enable_timer_wakeup(1000000ULL * DEEP_SLEEP_TIME_SEC);
delay(500);
esp_deep_sleep_start();
#endif
}
}