diff --git a/include/power.h b/include/power.h index 12e8c032..9fd1a73c 100644 --- a/include/power.h +++ b/include/power.h @@ -7,6 +7,7 @@ #include "i2c.h" #include "reset.h" +#include "lorawan.h" #define DEFAULT_VREF 1100 // tbd: use adc2_vref_to_gpio() for better estimate #define NO_OF_SAMPLES 64 // we do some multisampling to get better values @@ -15,11 +16,12 @@ #define BAT_MAX_VOLTAGE 4200 // millivolts #endif #ifndef BAT_MIN_VOLTAGE -#define BAT_MIN_VOLTAGE 2800 // millivolts +#define BAT_MIN_VOLTAGE 3100 // millivolts #endif +typedef uint8_t (*mapFn_t)(uint16_t, uint16_t, uint16_t); + uint16_t read_voltage(void); -uint8_t read_battlevel(void); void calibrate_voltage(void); bool batt_sufficient(void); @@ -34,4 +36,67 @@ void AXP192_showstatus(void); #endif // HAS_PMU +// The following map functions were taken from + +/* + Battery.h - Battery library + Copyright (c) 2014 Roberto Lo Giacco. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +// +// Plots of the functions below available at +// https://www.desmos.com/calculator/x0esk5bsrk +// + +/** + * Symmetric sigmoidal approximation + * https://www.desmos.com/calculator/7m9lu26vpy + * + * c - c / (1 + k*x/v)^3 + */ +static inline uint8_t sigmoidal(uint16_t voltage, uint16_t minVoltage, uint16_t maxVoltage) { + // slow + // uint8_t result = 110 - (110 / (1 + pow(1.468 * (voltage - minVoltage)/(maxVoltage - minVoltage), 6))); + + // steep + // uint8_t result = 102 - (102 / (1 + pow(1.621 * (voltage - minVoltage)/(maxVoltage - minVoltage), 8.1))); + + // normal + uint8_t result = 105 - (105 / (1 + pow(1.724 * (voltage - minVoltage)/(maxVoltage - minVoltage), 5.5))); + return result >= 100 ? 100 : result; +} + +/** + * Asymmetric sigmoidal approximation + * https://www.desmos.com/calculator/oyhpsu8jnw + * + * c - c / [1 + (k*x/v)^4.5]^3 + */ +static inline uint8_t asigmoidal(uint16_t voltage, uint16_t minVoltage, uint16_t maxVoltage) { + uint8_t result = 101 - (101 / pow(1 + pow(1.33 * (voltage - minVoltage)/(maxVoltage - minVoltage) ,4.5), 3)); + return result >= 100 ? 100 : result; +} + +/** + * Linear mapping + * https://www.desmos.com/calculator/sowyhttjta + * + * x * 100 / v + */ +static inline uint8_t linear(uint16_t voltage, uint16_t minVoltage, uint16_t maxVoltage) { + return (unsigned long)(voltage - minVoltage) * 100 / (maxVoltage - minVoltage); +} + +uint8_t read_battlevel(mapFn_t mapFunction = &sigmoidal); + #endif \ No newline at end of file diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 92d98acf..3bc4ccdb 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -68,10 +68,6 @@ void doHousekeeping() { #if (defined BAT_MEASURE_ADC || defined HAS_PMU) batt_level = read_battlevel(); ESP_LOGI(TAG, "Battery: %d%%", batt_level); -#if (HAS_LORA) - // to come with future LMIC version - // lora_setBattLevel(batt_level); -#endif #ifdef HAS_PMU AXP192_showstatus(); #endif diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 6a033580..4e3d7469 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -485,12 +485,10 @@ void lora_setBattLevel(uint8_t batt_percent) { #endif // HAS_PMU else - lmic_batt_level = static_cast( - (float)batt_percent / - (float)(MCMD_DEVS_BATT_MAX - MCMD_DEVS_BATT_MIN + 1) * 100.0f); + lmic_batt_level = + batt_percent / 100.0 * (MCMD_DEVS_BATT_MAX - MCMD_DEVS_BATT_MIN + 1); LMIC_setBattLevel(lmic_batt_level); - ESP_LOGD(TAG, "lmic_batt_level = %d", lmic_batt_level); } // event EV_RXCOMPLETE message handler diff --git a/src/power.cpp b/src/power.cpp index 47e4fb0a..c5da9a13 100644 --- a/src/power.cpp +++ b/src/power.cpp @@ -210,19 +210,29 @@ uint16_t read_voltage(void) { return voltage; } -uint8_t read_battlevel() { +uint8_t read_battlevel(mapFn_t mapFunction) { - // return the battery level in values 0 ... 255 [percent], - // values > 100 probably mean external power, depending on hardware + // returns the estimated battery level in values 0 ... 100 [percent], const uint16_t batt_voltage = read_voltage(); - float batt_percent_fl = (float)(batt_voltage - BAT_MIN_VOLTAGE) / - (float)(BAT_MAX_VOLTAGE - BAT_MIN_VOLTAGE) * 100.0f; - const uint8_t batt_percent = static_cast(batt_percent_fl); + uint8_t batt_percent; - ESP_LOGD(TAG, "batt_voltage = %dmV / batt_percent = %u%%", batt_voltage, + if (batt_voltage <= BAT_MIN_VOLTAGE) + batt_percent = 0; + else if (batt_voltage >= BAT_MAX_VOLTAGE) + batt_percent = 100; + else + batt_percent = + (*mapFunction)(batt_voltage, BAT_MIN_VOLTAGE, BAT_MAX_VOLTAGE); + + ESP_LOGD(TAG, "batt_voltage = %dmV / batt_percent = %d%%", batt_voltage, batt_percent); +#if (HAS_LORA) + // to come with future LMIC version + // lora_setBattLevel(batt_percent); +#endif + return batt_percent; }