mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-21 18:22:32 +00:00
Merge branch 'develop' into multi-message-Storage
This commit is contained in:
3
.github/workflows/release_channels.yml
vendored
3
.github/workflows/release_channels.yml
vendored
@@ -61,6 +61,9 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
# Always use master branch for version bumps
|
||||||
|
ref: master
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v6
|
||||||
|
|||||||
@@ -87,6 +87,9 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="2.7.16" date="2025-11-19">
|
||||||
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.16</url>
|
||||||
|
</release>
|
||||||
<release version="2.7.15" date="2025-11-13">
|
<release version="2.7.15" date="2025-11-13">
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.15</url>
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.15</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,3 +1,9 @@
|
|||||||
|
meshtasticd (2.7.16.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Version 2.7.16
|
||||||
|
|
||||||
|
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Wed, 19 Nov 2025 16:12:32 +0000
|
||||||
|
|
||||||
meshtasticd (2.7.15.0) unstable; urgency=medium
|
meshtasticd (2.7.15.0) unstable; urgency=medium
|
||||||
|
|
||||||
* Version 2.7.15
|
* Version 2.7.15
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level se
|
|||||||
|
|
||||||
#ifdef BATTERY_PIN
|
#ifdef BATTERY_PIN
|
||||||
|
|
||||||
static void adcEnable()
|
void battery_adcEnable()
|
||||||
{
|
{
|
||||||
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
|
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
|
||||||
#ifdef ADC_USE_PULLUP
|
#ifdef ADC_USE_PULLUP
|
||||||
@@ -215,7 +215,7 @@ static void adcEnable()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adcDisable()
|
static void battery_adcDisable()
|
||||||
{
|
{
|
||||||
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
|
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
|
||||||
#ifdef ADC_USE_PULLUP
|
#ifdef ADC_USE_PULLUP
|
||||||
@@ -321,7 +321,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
uint32_t raw = 0;
|
uint32_t raw = 0;
|
||||||
float scaled = 0;
|
float scaled = 0;
|
||||||
|
|
||||||
adcEnable();
|
battery_adcEnable();
|
||||||
#ifdef ARCH_ESP32 // ADC block for espressif platforms
|
#ifdef ARCH_ESP32 // ADC block for espressif platforms
|
||||||
raw = espAdcRead();
|
raw = espAdcRead();
|
||||||
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
|
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
|
||||||
@@ -333,7 +333,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
raw = raw / BATTERY_SENSE_SAMPLES;
|
raw = raw / BATTERY_SENSE_SAMPLES;
|
||||||
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
|
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
|
||||||
#endif
|
#endif
|
||||||
adcDisable();
|
battery_adcDisable();
|
||||||
|
|
||||||
if (!initial_read_done) {
|
if (!initial_read_done) {
|
||||||
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
|
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
|
||||||
@@ -909,13 +909,8 @@ void Power::readPowerStatus()
|
|||||||
low_voltage_counter++;
|
low_voltage_counter++;
|
||||||
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
|
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
|
||||||
if (low_voltage_counter > 10) {
|
if (low_voltage_counter > 10) {
|
||||||
#ifdef ARCH_NRF52
|
|
||||||
// We can't trigger deep sleep on NRF52, it's freezing the board
|
|
||||||
LOG_DEBUG("Low voltage detected, but not trigger deep sleep");
|
|
||||||
#else
|
|
||||||
LOG_INFO("Low voltage detected, trigger deep sleep");
|
LOG_INFO("Low voltage detected, trigger deep sleep");
|
||||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
low_voltage_counter = 0;
|
low_voltage_counter = 0;
|
||||||
|
|||||||
@@ -240,6 +240,9 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
|||||||
buffer[bytesRead] = b;
|
buffer[bytesRead] = b;
|
||||||
bytesRead++;
|
bytesRead++;
|
||||||
if ((bytesRead == 767) || (b == '\r')) {
|
if ((bytesRead == 767) || (b == '\r')) {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
|
LOG_DEBUG(debugmsg.c_str());
|
||||||
|
#endif
|
||||||
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
|
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
|
||||||
#ifdef GPS_DEBUG
|
#ifdef GPS_DEBUG
|
||||||
LOG_DEBUG("Found: %s", message); // Log the found message
|
LOG_DEBUG("Found: %s", message); // Log the found message
|
||||||
@@ -247,9 +250,6 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
|||||||
return GNSS_RESPONSE_OK;
|
return GNSS_RESPONSE_OK;
|
||||||
} else {
|
} else {
|
||||||
bytesRead = 0;
|
bytesRead = 0;
|
||||||
#ifdef GPS_DEBUG
|
|
||||||
LOG_DEBUG(debugmsg.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1275,6 +1275,24 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||||||
memset(&ublox_info, 0, sizeof(ublox_info));
|
memset(&ublox_info, 0, sizeof(ublox_info));
|
||||||
delay(100);
|
delay(100);
|
||||||
|
|
||||||
|
#if defined(PIN_GPS_RESET) && PIN_GPS_RESET != -1
|
||||||
|
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||||
|
delay(10);
|
||||||
|
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||||
|
|
||||||
|
// attempt to detect the chip based on boot messages
|
||||||
|
std::vector<ChipInfo> passive_detect = {
|
||||||
|
{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
|
||||||
|
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
|
||||||
|
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352},
|
||||||
|
{"UC6580", "UC6580", GNSS_MODEL_UC6580},
|
||||||
|
// as L76K is sort of a last ditch effort, we won't attempt to detect it by startup messages for now.
|
||||||
|
/*{"L76K", "SW=URANUS", GNSS_MODEL_MTK}*/};
|
||||||
|
GnssModel_t detectedDriver = getProbeResponse(500, passive_detect, serialSpeed);
|
||||||
|
if (detectedDriver != GNSS_MODEL_UNKNOWN) {
|
||||||
|
return detectedDriver;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
|
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
|
||||||
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||||
delay(20);
|
delay(20);
|
||||||
@@ -1473,12 +1491,12 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
||||||
#ifdef GPS_DEBUG
|
|
||||||
LOG_DEBUG(response);
|
|
||||||
#endif
|
|
||||||
// check if we can see our chips
|
// check if we can see our chips
|
||||||
for (const auto &chipInfo : responseMap) {
|
for (const auto &chipInfo : responseMap) {
|
||||||
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
|
LOG_DEBUG(response);
|
||||||
|
#endif
|
||||||
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
||||||
delete[] response; // Cleanup before return
|
delete[] response; // Cleanup before return
|
||||||
return chipInfo.driver;
|
return chipInfo.driver;
|
||||||
@@ -1486,6 +1504,9 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
|
LOG_DEBUG(response);
|
||||||
|
#endif
|
||||||
// Reset the response buffer for the next potential message
|
// Reset the response buffer for the next potential message
|
||||||
responseLen = 0;
|
responseLen = 0;
|
||||||
response[0] = '\0';
|
response[0] = '\0';
|
||||||
@@ -1572,8 +1593,6 @@ GPS *GPS::createGps()
|
|||||||
|
|
||||||
#ifdef PIN_GPS_RESET
|
#ifdef PIN_GPS_RESET
|
||||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
|
||||||
delay(10);
|
|
||||||
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
|||||||
#ifdef BUILD_EPOCH
|
#ifdef BUILD_EPOCH
|
||||||
if (tv.tv_sec < BUILD_EPOCH) {
|
if (tv.tv_sec < BUILD_EPOCH) {
|
||||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
||||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
LOG_WARN("Ignore time (%lu) before build epoch (%lu)!", printableEpoch, BUILD_EPOCH);
|
||||||
lastTimeValidationWarning = millis();
|
lastTimeValidationWarning = millis();
|
||||||
}
|
}
|
||||||
return RTCSetResultInvalidTime;
|
return RTCSetResultInvalidTime;
|
||||||
@@ -319,7 +319,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
|||||||
// Calculate max allowed time safely to avoid overflow in logging
|
// Calculate max allowed time safely to avoid overflow in logging
|
||||||
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
|
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
|
||||||
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
|
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
|
||||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch,
|
LOG_WARN("Ignore time (%lu) too far in the future (build epoch: %lu, max allowed: %lu)!", printableEpoch,
|
||||||
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
||||||
lastTimeValidationWarning = millis();
|
lastTimeValidationWarning = millis();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,3 +101,23 @@ void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength)
|
|||||||
else
|
else
|
||||||
snprintf(timeStr, maxLength, "unknown age");
|
snprintf(timeStr, maxLength, "unknown age");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getUptimeStr(uint32_t uptimeMillis, const char *prefix, char *uptimeStr, uint8_t maxLength, bool includeSecs)
|
||||||
|
{
|
||||||
|
uint32_t days = uptimeMillis / 86400000;
|
||||||
|
uint32_t hours = (uptimeMillis % 86400000) / 3600000;
|
||||||
|
uint32_t mins = (uptimeMillis % 3600000) / 60000;
|
||||||
|
uint32_t secs = (uptimeMillis % 60000) / 1000;
|
||||||
|
|
||||||
|
if (days) {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %ud %uh", prefix, days, hours);
|
||||||
|
} else if (hours) {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %uh %um", prefix, hours, mins);
|
||||||
|
} else if (!includeSecs) {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %um", prefix, mins);
|
||||||
|
} else if (mins) {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %um %us", prefix, mins, secs);
|
||||||
|
} else {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %us", prefix, secs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,3 +24,10 @@ bool deltaToTimestamp(uint32_t secondsAgo, uint8_t *hours, uint8_t *minutes, int
|
|||||||
* @param maxLength Maximum length of the resulting string buffer
|
* @param maxLength Maximum length of the resulting string buffer
|
||||||
*/
|
*/
|
||||||
void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength);
|
void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a compact human-readable string that only shows the largest non-zero time components.
|
||||||
|
* For example, 0 days 1 hour 2 minutes will display as "1h 2m" but 1 day 2 hours 3 minutes
|
||||||
|
* will display as "1d 2h".
|
||||||
|
*/
|
||||||
|
void getUptimeStr(uint32_t uptimeMillis, const char *prefix, char *uptimeStr, uint8_t maxLength, bool includeSecs = false);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "gps/RTC.h"
|
#include "gps/RTC.h"
|
||||||
#include "graphics/ScreenFonts.h"
|
#include "graphics/ScreenFonts.h"
|
||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
|
#include "graphics/TimeFormatters.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh/Channels.h"
|
#include "mesh/Channels.h"
|
||||||
@@ -649,17 +650,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
|
|
||||||
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line <= 5)) { // Only show uptime if the screen can show it
|
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line <= 5)) { // Only show uptime if the screen can show it
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
uint32_t uptime = millis() / 1000;
|
getUptimeStr(millis(), "Up", uptimeStr, sizeof(uptimeStr));
|
||||||
uint32_t days = uptime / 86400;
|
|
||||||
uint32_t hours = (uptime % 86400) / 3600;
|
|
||||||
uint32_t mins = (uptime % 3600) / 60;
|
|
||||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
|
||||||
if (days)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Up: %ud %uh", days, hours);
|
|
||||||
else if (hours)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Up: %uh %um", hours, mins);
|
|
||||||
else
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins);
|
|
||||||
textWidth = display->getStringWidth(uptimeStr);
|
textWidth = display->getStringWidth(uptimeStr);
|
||||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||||
display->drawString(nameX, getTextPositions(display)[line++], uptimeStr);
|
display->drawString(nameX, getTextPositions(display)[line++], uptimeStr);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "airtime.h"
|
#include "airtime.h"
|
||||||
#include "gps/GeoCoord.h"
|
#include "gps/GeoCoord.h"
|
||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
|
#include "graphics/TimeFormatters.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
@@ -390,17 +391,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
|||||||
// === 4. Uptime (only show if metric is present) ===
|
// === 4. Uptime (only show if metric is present) ===
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
||||||
uint32_t uptime = node->device_metrics.uptime_seconds;
|
getUptimeStr(node->device_metrics.uptime_seconds * 1000, " Up", uptimeStr, sizeof(uptimeStr));
|
||||||
uint32_t days = uptime / 86400;
|
|
||||||
uint32_t hours = (uptime % 86400) / 3600;
|
|
||||||
uint32_t mins = (uptime % 3600) / 60;
|
|
||||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
|
||||||
if (days)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %ud %uh", days, hours);
|
|
||||||
else if (hours)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %uh %um", hours, mins);
|
|
||||||
else
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins);
|
|
||||||
}
|
}
|
||||||
if (uptimeStr[0] && line < 5) {
|
if (uptimeStr[0] && line < 5) {
|
||||||
display->drawString(x, getTextPositions(display)[line++], uptimeStr);
|
display->drawString(x, getTextPositions(display)[line++], uptimeStr);
|
||||||
@@ -599,18 +590,8 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
drawNodes(display, x + 1, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
drawNodes(display, x + 1, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
||||||
#endif
|
#endif
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
uint32_t uptime = millis() / 1000;
|
|
||||||
uint32_t days = uptime / 86400;
|
|
||||||
uint32_t hours = (uptime % 86400) / 3600;
|
|
||||||
uint32_t mins = (uptime % 3600) / 60;
|
|
||||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(M5STACK_UNITC6L)
|
||||||
if (days)
|
getUptimeStr(millis(), "Up", uptimeStr, sizeof(uptimeStr));
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %ud %uh", days, hours);
|
|
||||||
else if (hours)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %uh %um", hours, mins);
|
|
||||||
else
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %um", mins);
|
|
||||||
#endif
|
#endif
|
||||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
||||||
|
|
||||||
@@ -1041,36 +1022,17 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
|||||||
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
||||||
// === Second Row: Last GPS Fix ===
|
// === Second Row: Last GPS Fix ===
|
||||||
if (gpsStatus->getLastFixMillis() > 0) {
|
if (gpsStatus->getLastFixMillis() > 0) {
|
||||||
uint32_t delta = (millis() - gpsStatus->getLastFixMillis()) / 1000; // seconds since last fix
|
uint32_t delta = millis() - gpsStatus->getLastFixMillis();
|
||||||
uint32_t days = delta / 86400;
|
char uptimeStr[32];
|
||||||
uint32_t hours = (delta % 86400) / 3600;
|
|
||||||
uint32_t mins = (delta % 3600) / 60;
|
|
||||||
uint32_t secs = delta % 60;
|
|
||||||
|
|
||||||
char buf[32];
|
|
||||||
#if defined(USE_EINK)
|
#if defined(USE_EINK)
|
||||||
// E-Ink: skip seconds, show only days/hours/mins
|
// E-Ink: skip seconds, show only days/hours/mins
|
||||||
if (days > 0) {
|
getUptimeStr(delta, "Last", uptimeStr, sizeof(uptimeStr), false);
|
||||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
|
||||||
} else if (hours > 0) {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
|
||||||
} else {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %um", mins);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
// Non E-Ink: include seconds where useful
|
// Non E-Ink: include seconds where useful
|
||||||
if (days > 0) {
|
getUptimeStr(delta, "Last", uptimeStr, sizeof(uptimeStr), true);
|
||||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
|
||||||
} else if (hours > 0) {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
|
||||||
} else if (mins > 0) {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %um %us", mins, secs);
|
|
||||||
} else {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %us", secs);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
display->drawString(0, getTextPositions(display)[line++], buf);
|
display->drawString(0, getTextPositions(display)[line++], uptimeStr);
|
||||||
} else {
|
} else {
|
||||||
display->drawString(0, getTextPositions(display)[line++], "Last: ?");
|
display->drawString(0, getTextPositions(display)[line++], "Last: ?");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshUtils.h"
|
#include "meshUtils.h"
|
||||||
|
#include "power.h"
|
||||||
|
|
||||||
|
#include <hal/nrf_lpcomp.h>
|
||||||
|
|
||||||
#ifdef BQ25703A_ADDR
|
#ifdef BQ25703A_ADDR
|
||||||
#include "BQ25713.h"
|
#include "BQ25713.h"
|
||||||
@@ -389,6 +392,23 @@ void cpuDeepSleep(uint32_t msecToWake)
|
|||||||
nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep
|
nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BATTERY_LPCOMP_INPUT
|
||||||
|
// Wake up if power rises again
|
||||||
|
nrf_lpcomp_config_t c;
|
||||||
|
c.reference = BATTERY_LPCOMP_THRESHOLD;
|
||||||
|
c.detection = NRF_LPCOMP_DETECT_UP;
|
||||||
|
c.hyst = NRF_LPCOMP_HYST_NOHYST;
|
||||||
|
nrf_lpcomp_configure(NRF_LPCOMP, &c);
|
||||||
|
nrf_lpcomp_input_select(NRF_LPCOMP, BATTERY_LPCOMP_INPUT);
|
||||||
|
nrf_lpcomp_enable(NRF_LPCOMP);
|
||||||
|
|
||||||
|
battery_adcEnable();
|
||||||
|
|
||||||
|
nrf_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START);
|
||||||
|
while (!nrf_lpcomp_event_check(NRF_LPCOMP, NRF_LPCOMP_EVENT_READY))
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
auto ok = sd_power_system_off();
|
auto ok = sd_power_system_off();
|
||||||
if (ok != NRF_SUCCESS) {
|
if (ok != NRF_SUCCESS) {
|
||||||
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
|
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
|
||||||
|
|||||||
@@ -144,4 +144,6 @@ class Power : private concurrency::OSThread
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void battery_adcEnable();
|
||||||
|
|
||||||
extern Power *power;
|
extern Power *power;
|
||||||
|
|||||||
@@ -210,6 +210,16 @@ No longer populated on PCB
|
|||||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
#define ADC_MULTIPLIER (4.916F)
|
#define ADC_MULTIPLIER (4.916F)
|
||||||
|
|
||||||
|
// rf52840 AIN2 = Pin 4
|
||||||
|
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_2
|
||||||
|
|
||||||
|
// We have AIN2 with a VBAT divider so AIN2 = VBAT * (100/490)
|
||||||
|
// We have the device going deep sleep under 3.1V, which is AIN2 = 0.63V
|
||||||
|
// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN2 = 0.67V
|
||||||
|
// Ratio 0.67/3.3 = 0.20, so we can pick a bit higher, 2/8 VDD, which means
|
||||||
|
// VBAT=4.04V
|
||||||
|
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_2_8
|
||||||
|
|
||||||
#define HAS_RTC 0
|
#define HAS_RTC 0
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,6 +267,20 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
|
|||||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
#define ADC_MULTIPLIER 1.73
|
#define ADC_MULTIPLIER 1.73
|
||||||
|
|
||||||
|
// RAK4630 AIN0 = nrf52840 AIN3 = Pin 5
|
||||||
|
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_3
|
||||||
|
|
||||||
|
// We have AIN3 with a VBAT divider so AIN3 = VBAT * (1.5/2.5)
|
||||||
|
// We have the device going deep sleep under 3.1V, which is AIN3 = 1.86V
|
||||||
|
// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN3 = 1.98V
|
||||||
|
// 1.98/3.3 = 6/10, but that's close to the VBAT divider, so we
|
||||||
|
// pick 6/8VDD, which means VBAT=4.1V.
|
||||||
|
// Reference:
|
||||||
|
// VDD=3.3V AIN3=5/8*VDD=2.06V VBAT=1.66*AIN3=3.41V
|
||||||
|
// VDD=3.3V AIN3=11/16*VDD=2.26V VBAT=1.66*AIN3=3.76V
|
||||||
|
// VDD=3.3V AIN3=6/8*VDD=2.47V VBAT=1.66*AIN3=4.1V
|
||||||
|
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_11_16
|
||||||
|
|
||||||
#define HAS_RTC 1
|
#define HAS_RTC 1
|
||||||
|
|
||||||
#define HAS_ETHERNET 1
|
#define HAS_ETHERNET 1
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[VERSION]
|
[VERSION]
|
||||||
major = 2
|
major = 2
|
||||||
minor = 7
|
minor = 7
|
||||||
build = 15
|
build = 16
|
||||||
|
|||||||
Reference in New Issue
Block a user