From 905b11e876806e87caa380f1d5fbec6ba7a1972f Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Tue, 17 Jun 2025 16:45:11 -0700 Subject: [PATCH 1/2] add board battery percentage defaults to lipo with no changes to existing variants - adds two chemistry types to start lipo and lifepo4 - adds getBattPercent to MainBoard - adds getBattType to MainBboard - companion UI now uses getBattPercent in renderBatteryIndicator --- examples/companion_radio/UITask.cpp | 8 +- examples/companion_radio/UITask.h | 2 +- src/MeshCore.h | 6 ++ src/helpers/Battery.cpp | 17 ++++ src/helpers/Battery.h | 122 ++++++++++++++++++++++++++++ 5 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 src/helpers/Battery.cpp create mode 100644 src/helpers/Battery.h diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index a7f03a26..6d7eb58d 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -143,11 +143,7 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i } } -void UITask::renderBatteryIndicator(uint16_t batteryMilliVolts) { - // Convert millivolts to percentage - const int minMilliVolts = 3000; // Minimum voltage (e.g., 3.0V) - const int maxMilliVolts = 4200; // Maximum voltage (e.g., 4.2V) - int batteryPercentage = ((batteryMilliVolts - minMilliVolts) * 100) / (maxMilliVolts - minMilliVolts); +void UITask::renderBatteryIndicator(uint16_t batteryPercentage) { if (batteryPercentage < 0) batteryPercentage = 0; // Clamp to 0% if (batteryPercentage > 100) batteryPercentage = 100; // Clamp to 100% @@ -222,7 +218,7 @@ void UITask::renderCurrScreen() { _display->print(_node_prefs->node_name); // battery voltage - renderBatteryIndicator(_board->getBattMilliVolts()); + renderBatteryIndicator(_board->getBattPercent()); // freq / sf _display->setCursor(0, 20); diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index 77ef875f..a0ff6aa5 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -51,7 +51,7 @@ class UITask { void renderCurrScreen(); void userLedHandler(); - void renderBatteryIndicator(uint16_t batteryMilliVolts); + void renderBatteryIndicator(uint16_t batteryPercentage); // Button action handlers void handleButtonAnyPress(); diff --git a/src/MeshCore.h b/src/MeshCore.h index d8886136..839bab8b 100644 --- a/src/MeshCore.h +++ b/src/MeshCore.h @@ -1,6 +1,7 @@ #pragma once #include +#include "helpers/Battery.h" #define MAX_HASH_SIZE 8 #define PUB_KEY_SIZE 32 @@ -36,6 +37,11 @@ namespace mesh { class MainBoard { public: virtual uint16_t getBattMilliVolts() = 0; + uint16_t getBattPercent() { + uint16_t mv = getBattMilliVolts(); + return batt_percent(getBattType(), mv); + } + uint8_t getBattType() { return BATT_LIPO; }; virtual const char* getManufacturerName() const = 0; virtual void onBeforeTransmit() { } virtual void onAfterTransmit() { } diff --git a/src/helpers/Battery.cpp b/src/helpers/Battery.cpp new file mode 100644 index 00000000..033f7ef1 --- /dev/null +++ b/src/helpers/Battery.cpp @@ -0,0 +1,17 @@ +#include +#include "Battery.h" + +uint16_t batt_percent(uint8_t batt, uint16_t mv) { + uint16_t last = mv; // set last to mv so it can never start greater than itself + uint16_t p = 0; + for (int i = 0; i < 102; i++) { // always 101 elements, 100 percent and 0 + // if we match the current value or are between the current and last value + // we return the lower of the the two, giving accuracy +/- 1% soc + if (mv <= last && mv >= batt_curve[i][batt]) { + p = batt_curve[i][batt_p_col]; + break; + } + last = batt_curve[i][batt]; + } + return p; +}; diff --git a/src/helpers/Battery.h b/src/helpers/Battery.h new file mode 100644 index 00000000..888f3017 --- /dev/null +++ b/src/helpers/Battery.h @@ -0,0 +1,122 @@ +/* +helpers/Battery.h defines battery chemistry types and their discharge curves +*/ + +// BATT_TYPE is a unique ID for battery chemistry type +// NOTE: enum for curve must match index in table curve +enum BATT_TYPE { BATT_LIPO, BATT_LIFEPO4 }; + +uint16_t batt_percent(uint8_t batt, uint16_t mv); + +// batt_p_col is the column index of the battery percentage in the below table +const int batt_p_col = 2; + +// batt_curve maps the battery voltage in mV to +// the approximate SoC for a typical cell +// Each column represents the mV for a given Soc foe that chemistry +// COL1 = LIPO, COL2 = LIFEPO4, COL3 = percent charge +// reference used https://blog.ampow.com/lipo-voltage-chart/ +// reference used https://cleversolarpower.com/lifepo4-voltage-chart/ +const uint16_t batt_curve[101][3] = { + { 4200, 3400, 100 }, + { 4190, 3395, 99 }, + { 4180, 3390, 98 }, + { 4170, 3385, 97 }, + { 4160, 3380, 96 }, + { 4150, 3375, 95 }, + { 4142, 3370, 94 }, + { 4134, 3365, 93 }, + { 4126, 3360, 92 }, + { 4118, 3355, 91 }, + { 4110, 3350, 90 }, + { 4104, 3347, 89 }, + { 4098, 3344, 88 }, + { 4092, 3341, 87 }, + { 4086, 3338, 86 }, + { 4080, 3335, 85 }, + { 4068, 3332, 84 }, + { 4056, 3329, 83 }, + { 4044, 3326, 82 }, + { 4032, 3323, 81 }, + { 4020, 3320, 80 }, + { 4012, 3318, 79 }, + { 4004, 3316, 78 }, + { 3996, 3314, 77 }, + { 3988, 3312, 76 }, + { 3980, 3310, 75 }, + { 3974, 3308, 74 }, + { 3968, 3306, 73 }, + { 3962, 3304, 72 }, + { 3956, 3302, 71 }, + { 3950, 3300, 70 }, + { 3942, 3297, 69 }, + { 3934, 3294, 68 }, + { 3926, 3291, 67 }, + { 3918, 3288, 66 }, + { 3910, 3285, 65 }, + { 3902, 3282, 64 }, + { 3894, 3279, 63 }, + { 3886, 3276, 62 }, + { 3878, 3273, 61 }, + { 3870, 3270, 60 }, + { 3866, 3269, 59 }, + { 3862, 3268, 58 }, + { 3858, 3267, 57 }, + { 3854, 3266, 56 }, + { 3850, 3265, 55 }, + { 3848, 3264, 54 }, + { 3846, 3263, 53 }, + { 3844, 3262, 52 }, + { 3842, 3261, 51 }, + { 3840, 3260, 50 }, + { 3836, 3259, 49 }, + { 3832, 3258, 48 }, + { 3828, 3257, 47 }, + { 3824, 3256, 46 }, + { 3820, 3255, 45 }, + { 3816, 3254, 44 }, + { 3812, 3253, 43 }, + { 3808, 3252, 42 }, + { 3804, 3251, 41 }, + { 3800, 3250, 40 }, + { 3798, 3247, 39 }, + { 3796, 3244, 38 }, + { 3794, 3241, 37 }, + { 3792, 3238, 36 }, + { 3790, 3235, 35 }, + { 3786, 3232, 34 }, + { 3782, 3229, 33 }, + { 3778, 3226, 32 }, + { 3774, 3223, 31 }, + { 3770, 3220, 30 }, + { 3766, 3218, 29 }, + { 3762, 3216, 28 }, + { 3758, 3214, 27 }, + { 3754, 3212, 26 }, + { 3750, 3210, 25 }, + { 3746, 3208, 24 }, + { 3742, 3206, 23 }, + { 3738, 3204, 22 }, + { 3724, 3202, 21 }, + { 3730, 3200, 20 }, + { 3726, 3180, 19 }, + { 3722, 3160, 18 }, + { 3718, 3140, 17 }, + { 3714, 3120, 16 }, + { 3710, 3100, 15 }, + { 3706, 3080, 14 }, + { 3702, 3060, 13 }, + { 3698, 3040, 12 }, + { 3694, 3020, 11 }, + { 3690, 3000, 10 }, + { 3674, 2950, 9 }, + { 3658, 2900, 8 }, + { 3642, 2850, 7 }, + { 3626, 2800, 6 }, + { 3610, 2750, 5 }, + { 3542, 2700, 4 }, + { 3474, 2650, 3 }, + { 3406, 2600, 2 }, + { 3338, 2550, 1 }, + { 3270, 2500, 0 } +}; From f95d4449f40e3c232a7e5027638571df48359847 Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Fri, 20 Jun 2025 14:27:13 -0700 Subject: [PATCH 2/2] fix off by one in batt_percent loop --- src/helpers/Battery.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/helpers/Battery.cpp b/src/helpers/Battery.cpp index 033f7ef1..3deb5db6 100644 --- a/src/helpers/Battery.cpp +++ b/src/helpers/Battery.cpp @@ -4,7 +4,8 @@ uint16_t batt_percent(uint8_t batt, uint16_t mv) { uint16_t last = mv; // set last to mv so it can never start greater than itself uint16_t p = 0; - for (int i = 0; i < 102; i++) { // always 101 elements, 100 percent and 0 + // 101 elements including 0 percentile + for (int i = 0; i < 101; i++) { // if we match the current value or are between the current and last value // we return the lower of the the two, giving accuracy +/- 1% soc if (mv <= last && mv >= batt_curve[i][batt]) {