sforkowany z mirror/meshtastic-firmware
Merge remote-tracking branch 'root/master' into dev
commit
0c0b2446b7
|
@ -75,6 +75,16 @@ void readPowerStatus()
|
||||||
powerStatus.haveBattery = axp.isBatteryConnect();
|
powerStatus.haveBattery = axp.isBatteryConnect();
|
||||||
if (powerStatus.haveBattery) {
|
if (powerStatus.haveBattery) {
|
||||||
powerStatus.batteryVoltageMv = axp.getBattVoltage();
|
powerStatus.batteryVoltageMv = axp.getBattVoltage();
|
||||||
|
// If the AXP192 returns a valid battery percentage, use it
|
||||||
|
if (axp.getBattPercentage() >= 0) {
|
||||||
|
powerStatus.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
|
||||||
|
int calculatedPercentage = ((powerStatus.batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY);
|
||||||
|
powerStatus.batteryChargePercent = (calculatedPercentage < 0) ? 0 : (calculatedPercentage > 100) ? 100 : calculatedPercentage;
|
||||||
|
}
|
||||||
|
DEBUG_MSG("Battery %dmV %d%%\n", powerStatus.batteryVoltageMv, powerStatus.batteryChargePercent);
|
||||||
}
|
}
|
||||||
powerStatus.usb = axp.isVBUSPlug();
|
powerStatus.usb = axp.isVBUSPlug();
|
||||||
powerStatus.charging = axp.isChargeing();
|
powerStatus.charging = axp.isChargeing();
|
||||||
|
@ -205,15 +215,6 @@ uint32_t axpDebugRead()
|
||||||
Periodic axpDebugOutput(axpDebugRead);
|
Periodic axpDebugOutput(axpDebugRead);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* Per @spattinson
|
|
||||||
* MIN_BAT_MILLIVOLTS seems high. Typical 18650 are different chemistry to LiPo, even for LiPos that chart seems a bit off, other
|
|
||||||
* charts put 3690mV at about 30% for a lipo, for 18650 i think 10% remaining iis in the region of 3.2-3.3V. Reference 1st graph
|
|
||||||
* in [this test report](https://lygte-info.dk/review/batteries2012/Samsung%20INR18650-30Q%203000mAh%20%28Pink%29%20UK.html)
|
|
||||||
* looking at the red line - discharge at 0.2A - he gets a capacity of 2900mah, 90% of 2900 = 2610, that point in the graph looks
|
|
||||||
* to be a shade above 3.2V
|
|
||||||
*/
|
|
||||||
#define MIN_BAT_MILLIVOLTS 3250 // millivolts. 10% per https://blog.ampow.com/lipo-voltage-chart/
|
|
||||||
|
|
||||||
/// loop code specific to ESP32 targets
|
/// loop code specific to ESP32 targets
|
||||||
void esp32Loop()
|
void esp32Loop()
|
||||||
|
|
|
@ -68,19 +68,6 @@ void perhapsSetRTC(struct tm &t)
|
||||||
perhapsSetRTC(&tv);
|
perhapsSetRTC(&tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a string representation of the DOP
|
|
||||||
// based on Wikipedia "meaning of DOP values" https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)#Meaning_of_DOP_Values
|
|
||||||
const char *getDOPString(uint32_t dop) {
|
|
||||||
dop = dop / 100;
|
|
||||||
if(dop <= 1) return "GPS Ideal";
|
|
||||||
if(dop <= 2) return "GPS Exc.";
|
|
||||||
if(dop <= 5) return "GPS Good";
|
|
||||||
if(dop <= 10) return "GPS Mod.";
|
|
||||||
if(dop <= 20) return "GPS Fair";
|
|
||||||
if(dop > 0) return "GPS Poor";
|
|
||||||
return "invalid dop";
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
uint32_t getTime()
|
uint32_t getTime()
|
||||||
|
|
|
@ -4,7 +4,12 @@ const uint8_t SATELLITE_IMAGE[] PROGMEM = {0x00, 0x08, 0x00, 0x1C, 0x00, 0x0E, 0
|
||||||
0xF8, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC8, 0x01, 0x9C, 0x54,
|
0xF8, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC8, 0x01, 0x9C, 0x54,
|
||||||
0x0E, 0x52, 0x07, 0x48, 0x02, 0x26, 0x00, 0x10, 0x00, 0x0E};
|
0x0E, 0x52, 0x07, 0x48, 0x02, 0x26, 0x00, 0x10, 0x00, 0x0E};
|
||||||
|
|
||||||
const
|
const uint8_t imgUSB[] PROGMEM = { 0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C };
|
||||||
|
const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08, 0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22 };
|
||||||
|
const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C };
|
||||||
|
const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF };
|
||||||
|
const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF };
|
||||||
|
|
||||||
#include "icon.xbm"
|
#include "icon.xbm"
|
||||||
|
|
||||||
// We now programmatically draw our compass
|
// We now programmatically draw our compass
|
||||||
|
|
|
@ -361,7 +361,6 @@ void loop()
|
||||||
screen.debug()->setNodeNumbersStatus(nodeDB.getNumOnlineNodes(), nodeDB.getNumNodes());
|
screen.debug()->setNodeNumbersStatus(nodeDB.getNumOnlineNodes(), nodeDB.getNumNodes());
|
||||||
screen.debug()->setChannelNameStatus(channelSettings.name);
|
screen.debug()->setChannelNameStatus(channelSettings.name);
|
||||||
screen.debug()->setPowerStatus(powerStatus);
|
screen.debug()->setPowerStatus(powerStatus);
|
||||||
screen.debug()->setGPSStatus(gps->isConnected ? (gps->hasLock() ? getDOPString(gps->dop) : "No Sats") : "No GPS");
|
|
||||||
|
|
||||||
// No GPS lock yet, let the OS put the main CPU in low power mode for 100ms (or until another interrupt comes in)
|
// No GPS lock yet, let the OS put the main CPU in low power mode for 100ms (or until another interrupt comes in)
|
||||||
// i.e. don't just keep spinning in loop as fast as we can.
|
// i.e. don't just keep spinning in loop as fast as we can.
|
||||||
|
|
15
src/power.h
15
src/power.h
|
@ -1,5 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per @spattinson
|
||||||
|
* MIN_BAT_MILLIVOLTS seems high. Typical 18650 are different chemistry to LiPo, even for LiPos that chart seems a bit off, other
|
||||||
|
* charts put 3690mV at about 30% for a lipo, for 18650 i think 10% remaining iis in the region of 3.2-3.3V. Reference 1st graph
|
||||||
|
* in [this test report](https://lygte-info.dk/review/batteries2012/Samsung%20INR18650-30Q%203000mAh%20%28Pink%29%20UK.html)
|
||||||
|
* looking at the red line - discharge at 0.2A - he gets a capacity of 2900mah, 90% of 2900 = 2610, that point in the graph looks
|
||||||
|
* to be a shade above 3.2V
|
||||||
|
*/
|
||||||
|
#define MIN_BAT_MILLIVOLTS 3250 // millivolts. 10% per https://blog.ampow.com/lipo-voltage-chart/
|
||||||
|
|
||||||
|
#define BAT_MILLIVOLTS_FULL 4100
|
||||||
|
#define BAT_MILLIVOLTS_EMPTY 3500
|
||||||
|
|
||||||
namespace meshtastic
|
namespace meshtastic
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -9,6 +22,8 @@ struct PowerStatus {
|
||||||
bool haveBattery;
|
bool haveBattery;
|
||||||
/// Battery voltage in mV, valid if haveBattery is true
|
/// Battery voltage in mV, valid if haveBattery is true
|
||||||
int batteryVoltageMv;
|
int batteryVoltageMv;
|
||||||
|
/// Battery charge percentage, either read directly or estimated
|
||||||
|
int batteryChargePercent;
|
||||||
/// Whether USB is connected
|
/// Whether USB is connected
|
||||||
bool usb;
|
bool usb;
|
||||||
/// Whether we are charging the battery
|
/// Whether we are charging the battery
|
||||||
|
|
|
@ -54,6 +54,8 @@ static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
||||||
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
||||||
static char btPIN[16] = "888888";
|
static char btPIN[16] = "888888";
|
||||||
|
|
||||||
|
uint8_t imgBattery[16] = { 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C };
|
||||||
|
|
||||||
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
// draw an xbm image.
|
// draw an xbm image.
|
||||||
|
@ -164,6 +166,47 @@ static uint32_t drawRows(OLEDDisplay *display, int16_t x, int16_t y, const char
|
||||||
return yo;
|
return yo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage.
|
||||||
|
static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, PowerStatus *powerStatus) {
|
||||||
|
static const uint8_t powerBar[3] = { 0x81, 0xBD, 0xBD };
|
||||||
|
static const uint8_t lightning[8] = { 0xA1, 0xA1, 0xA5, 0xAD, 0xB5, 0xA5, 0x85, 0x85 };
|
||||||
|
// Clear the bar area on the battery image
|
||||||
|
for (int i = 1; i < 14; i++) {
|
||||||
|
imgBuffer[i] = 0x81;
|
||||||
|
}
|
||||||
|
// If charging, draw a charging indicator
|
||||||
|
if (powerStatus->charging) {
|
||||||
|
memcpy(imgBuffer + 3, lightning, 8);
|
||||||
|
// If not charging, Draw power bars
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if(powerStatus->batteryChargePercent >= 25 * i) memcpy(imgBuffer + 1 + (i * 3), powerBar, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display->drawFastImage(x, y, 16, 8, imgBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw nodes status
|
||||||
|
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, int nodesOnline, int nodesTotal) {
|
||||||
|
char usersString[20];
|
||||||
|
sprintf(usersString, "%d/%d", nodesOnline, nodesTotal);
|
||||||
|
display->drawFastImage(x, y, 8, 8, imgUser);
|
||||||
|
display->drawString(x + 10, y - 2, usersString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw GPS status summary
|
||||||
|
static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, GPS *gps) {
|
||||||
|
if(!gps->isConnected) { display->drawString(x, y - 2, "No GPS"); return; }
|
||||||
|
display->drawFastImage(x, y, 6, 8, gps->hasLock() ? imgPositionSolid : imgPositionEmpty );
|
||||||
|
if(!gps->hasLock()) { display->drawString(x + 8, y - 2, "No sats"); return; }
|
||||||
|
if(gps->dop <= 100) { display->drawString(x + 8, y - 2, "Ideal"); return; }
|
||||||
|
if(gps->dop <= 200) { display->drawString(x + 8, y - 2, "Exc."); return; }
|
||||||
|
if(gps->dop <= 500) { display->drawString(x + 8, y - 2, "Good"); return; }
|
||||||
|
if(gps->dop <= 1000) { display->drawString(x + 8, y - 2, "Mod."); return; }
|
||||||
|
if(gps->dop <= 2000) { display->drawString(x + 8, y - 2, "Fair"); return; }
|
||||||
|
if(gps->dop > 0) { display->drawString(x + 8, y - 2, "Poor"); return; }
|
||||||
|
}
|
||||||
|
|
||||||
/// Ported from my old java code, returns distance in meters along the globe
|
/// Ported from my old java code, returns distance in meters along the globe
|
||||||
/// surface (by magic?)
|
/// surface (by magic?)
|
||||||
static float latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b)
|
static float latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b)
|
||||||
|
@ -656,33 +699,21 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||||
// The coordinates define the left starting point of the text
|
// The coordinates define the left starting point of the text
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
|
||||||
char usersStr[20];
|
|
||||||
char channelStr[20];
|
char channelStr[20];
|
||||||
char batStr[20];
|
|
||||||
char gpsStr[20];
|
|
||||||
{
|
{
|
||||||
LockGuard guard(&lock);
|
LockGuard guard(&lock);
|
||||||
snprintf(usersStr, sizeof(usersStr), "Users %d/%d", nodesOnline, nodesTotal);
|
snprintf(channelStr, sizeof(channelStr), "#%s", channelName.c_str());
|
||||||
snprintf(channelStr, sizeof(channelStr), "%s", channelName.c_str());
|
|
||||||
if (powerStatus.haveBattery) {
|
|
||||||
// TODO: draw a battery icon instead of letter "B".
|
|
||||||
int batV = powerStatus.batteryVoltageMv / 1000;
|
|
||||||
int batCv = (powerStatus.batteryVoltageMv % 1000) / 10;
|
|
||||||
snprintf(batStr, sizeof(batStr), "B %01d.%02dV%c%c", batV, batCv, powerStatus.charging ? '+' : ' ',
|
|
||||||
powerStatus.usb ? 'U' : ' ');
|
|
||||||
} else {
|
|
||||||
snprintf(batStr, sizeof(batStr), "%s", powerStatus.usb ? "USB" : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gpsStatus.empty()) {
|
// Display power status
|
||||||
snprintf(gpsStr, sizeof(gpsStr), "%s", gpsStatus.c_str());
|
if (powerStatus.haveBattery) drawBattery(display, x, y + 2, imgBattery, &powerStatus); else display->drawFastImage(x, y + 2, 16, 8, powerStatus.usb ? imgUSB : imgPower);
|
||||||
} else {
|
// Display nodes status
|
||||||
gpsStr[0] = '\0'; // Just show empty string.
|
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodesOnline, nodesTotal);
|
||||||
}
|
// Display GPS status
|
||||||
|
drawGPS(display, x + (SCREEN_WIDTH * 0.66), y + 2, gps);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *fields[] = {batStr, gpsStr, usersStr, channelStr, nullptr};
|
const char *fields[] = {channelStr, nullptr};
|
||||||
uint32_t yo = drawRows(display, x, y, fields);
|
uint32_t yo = drawRows(display, x, y + 12, fields);
|
||||||
|
|
||||||
display->drawLogBuffer(x, yo);
|
display->drawLogBuffer(x, yo);
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue