diff --git a/platformio.ini b/platformio.ini
index f3a4db2a6..1b11e1cbc 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -9,7 +9,7 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
-default_envs = tbeam
+default_envs = tbeam
[common]
; common is not currently used
@@ -69,7 +69,8 @@ lib_deps =
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
https://github.com/meshtastic/RadioLib.git#d6b12f7eb0a06bd2414c79b437b25d377e3f603f
https://github.com/meshtastic/TinyGPSPlus.git
-
+ https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
+
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
platform = espressif32
@@ -99,7 +100,6 @@ extends = esp32_base
board = ttgo-t-beam
lib_deps =
${env.lib_deps}
- https://github.com/meshtastic/AXP202X_Library.git
build_flags =
${esp32_base.build_flags} -D TBEAM_V10
diff --git a/src/Power.cpp b/src/Power.cpp
index 23332698b..7bfa42d29 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -1,27 +1,92 @@
#include "power.h"
#include "PowerFSM.h"
#include "main.h"
-#include "utils.h"
#include "sleep.h"
-
-#ifdef TBEAM_V10
+#include "utils.h"
// FIXME. nasty hack cleanup how we load axp192
#undef AXP192_SLAVE_ADDRESS
#include "axp20x.h"
+
+#ifdef TBEAM_V10
AXP20X_Class axp;
+#endif
+
bool pmu_irq = false;
Power *power;
-bool Power::setup()
+/**
+ * If this board has a battery level sensor, set this to a valid implementation
+ */
+static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level sensor
+
+/**
+ * A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input
+ */
+class AnalogBatteryLevel : public HasBatteryLevel
{
+ /**
+ * Battery state of charge, from 0 to 100 or -1 for unknown
+ *
+ * FIXME - use a lipo lookup table, the current % full is super wrong
+ */
+ virtual int getBattPercentage()
+ {
+ float v = getBattVoltage();
- axp192Init();
- concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
- setPeriod(1);
+ if (v < 2.1)
+ return -1;
- return axp192_found;
+ return 100 * (getBattVoltage() - 3.27) / (4.2 - 3.27);
+ }
+
+ /**
+ * The raw voltage of the battery or NAN if unknown
+ */
+ virtual float getBattVoltage()
+ {
+ return
+#ifdef BATTERY_PIN
+ analogRead(BATTERY_PIN) * 2.0 * (3.3 / 1024.0);
+#else
+ NAN;
+#endif
+ }
+
+ /**
+ * return true if there is a battery installed in this unit
+ */
+ virtual bool isBatteryConnect() { return true; }
+} analogLevel;
+
+bool Power::analogInit()
+{
+#ifdef BATTERY_PIN
+ DEBUG_MSG("Using analog input for battery level\n");
+ adcAttachPin(BATTERY_PIN);
+ // adcStart(BATTERY_PIN);
+ analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
+ batteryLevel = &analogLevel;
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool Power::setup()
+{
+ bool found = axp192Init();
+
+ if (!found) {
+ found = analogInit();
+ }
+ if (found) {
+ concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
+ setPeriod(1);
+ }
+
+ return found;
}
/// Reads power status to powerStatus singleton.
@@ -29,42 +94,45 @@ bool Power::setup()
// TODO(girts): move this and other axp stuff to power.h/power.cpp.
void Power::readPowerStatus()
{
- bool hasBattery = axp.isBatteryConnect();
- int batteryVoltageMv = 0;
- uint8_t batteryChargePercent = 0;
- if (hasBattery) {
- batteryVoltageMv = axp.getBattVoltage();
- // If the AXP192 returns a valid battery percentage, use it
- if (axp.getBattPercentage() >= 0) {
- batteryChargePercent = axp.getBattPercentage();
- } else {
- // If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
- // In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in power.h
- batteryChargePercent = clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)), 0, 100);
+ if (batteryLevel) {
+ bool hasBattery = batteryLevel->isBatteryConnect();
+ int batteryVoltageMv = 0;
+ uint8_t batteryChargePercent = 0;
+ if (hasBattery) {
+ batteryVoltageMv = batteryLevel->getBattVoltage();
+ // If the AXP192 returns a valid battery percentage, use it
+ if (batteryLevel->getBattPercentage() >= 0) {
+ batteryChargePercent = batteryLevel->getBattPercentage();
+ } else {
+ // If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
+ // In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in
+ // power.h
+ batteryChargePercent =
+ clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)),
+ 0, 100);
+ }
}
+
+ // Notify any status instances that are observing us
+ const meshtastic::PowerStatus powerStatus = meshtastic::PowerStatus(
+ hasBattery, batteryLevel->isVBUSPlug(), batteryLevel->isChargeing(), batteryVoltageMv, batteryChargePercent);
+ newStatus.notifyObservers(&powerStatus);
+
+ // If we have a battery at all and it is less than 10% full, force deep sleep
+ if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
+ powerFSM.trigger(EVENT_LOW_BATTERY);
}
-
- // Notify any status instances that are observing us
- const meshtastic::PowerStatus powerStatus = meshtastic::PowerStatus(hasBattery, axp.isVBUSPlug(), axp.isChargeing(), batteryVoltageMv, batteryChargePercent);
- newStatus.notifyObservers(&powerStatus);
-
- // If we have a battery at all and it is less than 10% full, force deep sleep
- if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() &&
- axp.getBattVoltage() < MIN_BAT_MILLIVOLTS)
- powerFSM.trigger(EVENT_LOW_BATTERY);
}
-void Power::doTask()
+void Power::doTask()
{
readPowerStatus();
-
+
// Only read once every 20 seconds once the power status for the app has been initialized
- if(statusHandler && statusHandler->isInitialized())
+ if (statusHandler && statusHandler->isInitialized())
setPeriod(1000 * 20);
}
-#endif // TBEAM_V10
-#ifdef AXP192_SLAVE_ADDRESS
/**
* Init the power manager chip
*
@@ -74,10 +142,13 @@ void Power::doTask()
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
*/
-void Power::axp192Init()
+bool Power::axp192Init()
{
+#ifdef TBEAM_V10
if (axp192_found) {
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
+ batteryLevel = &axp;
+
DEBUG_MSG("AXP192 Begin PASS\n");
// axp.setChgLEDMode(LED_BLINK_4HZ);
@@ -135,12 +206,16 @@ void Power::axp192Init()
} else {
DEBUG_MSG("AXP192 not found\n");
}
-}
+
+ return axp192_found;
+#else
+ return false;
#endif
+}
-void Power::loop()
+
+void Power::loop()
{
-
#ifdef PMU_IRQ
if (pmu_irq) {
pmu_irq = false;
@@ -174,6 +249,5 @@ void Power::loop()
axp.clearIRQ();
}
-#endif // T_BEAM_V10
-
+#endif
}
diff --git a/src/configuration.h b/src/configuration.h
index 89e8ef81d..613f20d87 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -167,7 +167,6 @@ along with this program. If not, see .
// Leave undefined to disable our PMU IRQ handler
#define PMU_IRQ 35
-
#define AXP192_SLAVE_ADDRESS 0x34
#elif defined(TBEAM_V07)
@@ -180,6 +179,7 @@ along with this program. If not, see .
#define I2C_SCL 22
#define BUTTON_PIN 39
+// #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#ifndef USE_JTAG
#define RF95_RESET 23
@@ -278,6 +278,8 @@ along with this program. If not, see .
#define GPS_RX_PIN 36
#define GPS_TX_PIN 39
+// #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
+
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
diff --git a/src/main.cpp b/src/main.cpp
index b8ee00219..3cc4097d6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -210,13 +210,11 @@ void setup()
esp32Setup();
#endif
-#ifdef TBEAM_V10
// Currently only the tbeam has a PMU
power = new Power();
power->setup();
power->setStatusHandler(powerStatus);
powerStatus->observe(&power->newStatus);
-#endif
#ifdef NRF52_SERIES
nrf52Setup();
diff --git a/src/power.h b/src/power.h
index dd6b8ce87..a779089ad 100644
--- a/src/power.h
+++ b/src/power.h
@@ -1,6 +1,6 @@
#pragma once
-#include "concurrency/PeriodicTask.h"
#include "PowerStatus.h"
+#include "concurrency/PeriodicTask.h"
/**
* Per @spattinson
@@ -18,23 +18,23 @@
class Power : public concurrency::PeriodicTask
{
- public:
-
+ public:
Observable newStatus;
void readPowerStatus();
void loop();
virtual bool setup();
virtual void doTask();
- void setStatusHandler(meshtastic::PowerStatus *handler)
- {
- statusHandler = handler;
- }
-
- protected:
- meshtastic::PowerStatus *statusHandler;
- virtual void axp192Init();
+ void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; }
+ protected:
+ meshtastic::PowerStatus *statusHandler;
+
+ /// Setup a axp192, return true if found
+ bool axp192Init();
+
+ /// Setup a simple ADC input based battery sensor
+ bool analogInit();
};
extern Power *power;
\ No newline at end of file