fix(trail,batt): GPX NUL in stream + battery curve top at 4170 mV

- Trail.h gpxWaypoints/gpxPoint: snprintf truncation clamp was `> sizeof`
  (writing the NUL terminator into the XML stream); corrected to
  `>= sizeof - 1` at all 3 sites (<wpt>, <time>, <trkpt>).
- UITask.cpp battMvToPercent: raise 100% ceiling from 4200 → 4170 mV —
  the board never charges to 4200, so the indicator was stuck at ~97%.
- Trail.h header comment: corrected RAM cost from "256×12 B=3 KB" to
  actual CAPACITY(512)×16 B=8 KB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-06-09 17:00:00 +02:00
co-authored by Claude Sonnet 4.6
parent e6f8fb99c7
commit 2cc68fb987
2 changed files with 7 additions and 6 deletions
+6 -5
View File
@@ -6,8 +6,9 @@
#include <time.h> #include <time.h>
// RAM-only GPS trail ring buffer. // RAM-only GPS trail ring buffer.
// Storage cost: 256 × 12 B = 3 KB. The trail survives auto-off (only the // Storage cost: CAPACITY(512) × sizeof(TrailPoint)(16 B, padded) = 8 KB,
// display blanks) but is lost on reboot — user explicitly snapshots to a // always resident (UITask::_trail member). The trail survives auto-off (only
// the display blanks) but is lost on reboot — user explicitly snapshots to a
// LittleFS slot before powering down to keep it. // LittleFS slot before powering down to keep it.
struct TrailPoint { struct TrailPoint {
@@ -265,7 +266,7 @@ public:
"<wpt lat=\"%.6f\" lon=\"%.6f\"><name>%s</name>", "<wpt lat=\"%.6f\" lon=\"%.6f\"><name>%s</name>",
w.lat_1e6 / 1.0e6, w.lon_1e6 / 1.0e6, esc); w.lat_1e6 / 1.0e6, w.lon_1e6 / 1.0e6, esc);
if (len > 0) { if (len > 0) {
if ((size_t)len > sizeof(buf)) len = sizeof(buf); if ((size_t)len >= sizeof(buf)) len = sizeof(buf) - 1; // truncated: emit chars only, not the NUL
n += out.write((const uint8_t*)buf, (size_t)len); n += out.write((const uint8_t*)buf, (size_t)len);
} }
if (w.ts > 1000000000UL) { // append <time> when the RTC was set if (w.ts > 1000000000UL) { // append <time> when the RTC was set
@@ -276,7 +277,7 @@ public:
"<time>%04d-%02d-%02dT%02d:%02d:%02dZ</time>", "<time>%04d-%02d-%02dT%02d:%02d:%02dZ</time>",
gt->tm_year + 1900, gt->tm_mon + 1, gt->tm_mday, gt->tm_year + 1900, gt->tm_mon + 1, gt->tm_mday,
gt->tm_hour, gt->tm_min, gt->tm_sec); gt->tm_hour, gt->tm_min, gt->tm_sec);
if (len > 0) { if ((size_t)len > sizeof(buf)) len = sizeof(buf); if (len > 0) { if ((size_t)len >= sizeof(buf)) len = sizeof(buf) - 1;
n += out.write((const uint8_t*)buf, (size_t)len); } n += out.write((const uint8_t*)buf, (size_t)len); }
} }
} }
@@ -314,7 +315,7 @@ public:
gt->tm_year + 1900, gt->tm_mon + 1, gt->tm_mday, gt->tm_year + 1900, gt->tm_mon + 1, gt->tm_mday,
gt->tm_hour, gt->tm_min, gt->tm_sec); gt->tm_hour, gt->tm_min, gt->tm_sec);
if (len < 0) return n; if (len < 0) return n;
if ((size_t)len > sizeof(buf)) len = sizeof(buf); // snprintf returns intended size if ((size_t)len >= sizeof(buf)) len = sizeof(buf) - 1; // truncated: emit chars only, not the NUL
n += out.write((const uint8_t*)buf, (size_t)len); n += out.write((const uint8_t*)buf, (size_t)len);
return n; return n;
} }
+1 -1
View File
@@ -134,7 +134,7 @@ static int battMvToPercent(int mv, int low_mv) {
static const struct { uint16_t mv; uint8_t pct; } CURVE[] = { static const struct { uint16_t mv; uint8_t pct; } CURVE[] = {
{3200, 0}, {3300, 3}, {3400, 8}, {3500, 15}, {3200, 0}, {3300, 3}, {3400, 8}, {3500, 15},
{3600, 25}, {3650, 33}, {3700, 45}, {3750, 58}, {3600, 25}, {3650, 33}, {3700, 45}, {3750, 58},
{3800, 68}, {3900, 77}, {4000, 86}, {4100, 93}, {4200, 100} {3800, 68}, {3900, 77}, {4000, 86}, {4100, 93}, {4170, 100}
}; };
static const int CURVE_LEN = sizeof(CURVE) / sizeof(CURVE[0]); static const int CURVE_LEN = sizeof(CURVE) / sizeof(CURVE[0]);
auto curveAt = [&](int v) -> int { auto curveAt = [&](int v) -> int {