From 7f17c3aeabd099cd4146c209d205d1ab66d9e222 Mon Sep 17 00:00:00 2001 From: "Valentin V. Bartenev" Date: Sat, 16 May 2026 15:29:11 +0300 Subject: [PATCH] Web: fix bogus packets/error_rate delta at SD archive restore boundary restoreSummaryLog() seeds the ring buffer with one sample from the previous session (summary.latest). The next live sample has reset counters and uptime starting from zero, so the delta across that boundary is meaningless. For the packets series this produced a zero point (same symptom as the first-sample zero fixed in 1018404b, but at the restore boundary instead). For error_rate it produced an inflated value because the counter difference wraps around. Fix by skipping any sample whose uptime_secs does not exceed the previous sample's uptime_secs. In buildPointValue this returns false; in the buildSeriesJson packets loop it skips emission and does not advance previous. Also: move have_previous = false into the else branch (the packets branch does not use it), drop the now-redundant >= guards in favour of direct uint32_t subtraction, and replace a C-style cast with static_cast for consistency. --- src/helpers/StatsHistory.cpp | 42 +++++++++++++++++------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/helpers/StatsHistory.cpp b/src/helpers/StatsHistory.cpp index 62ff44fc..4a6fc754 100644 --- a/src/helpers/StatsHistory.cpp +++ b/src/helpers/StatsHistory.cpp @@ -228,16 +228,16 @@ bool buildPointValue(const HistorySample& sample, const HistorySample* previous, return true; } if (strcmp(series, "packets") == 0) { - if (previous == nullptr) { + if (previous == nullptr || sample.uptime_secs < previous->uptime_secs) { return false; } - const uint32_t curr_total = sample.packets_sent + sample.packets_recv; - const uint32_t prev_total = previous->packets_sent + previous->packets_recv; - value = static_cast(curr_total >= prev_total ? (curr_total - prev_total) : 0); + const uint32_t d_recv = sample.packets_recv - previous->packets_recv; + const uint32_t d_sent = sample.packets_sent - previous->packets_sent; + value = static_cast(d_recv + d_sent); return true; } if (strcmp(series, "error_rate") == 0) { - if (previous == nullptr) { + if (previous == nullptr || sample.uptime_secs < previous->uptime_secs) { return false; } const uint32_t d_errors = sample.recv_errors - previous->recv_errors; @@ -246,7 +246,7 @@ bool buildPointValue(const HistorySample& sample, const HistorySample* previous, if (total == 0) { return false; } - value = (int)((d_errors * 1000u) / total); + value = static_cast((d_errors * 1000u) / total); return true; } if (strcmp(series, "voltage") == 0) { @@ -1342,30 +1342,28 @@ bool StatsHistory::buildSeriesJson(const char* series, char* buffer, size_t buff offset = static_cast(header_written); emitted = 0; size_t valid_emitted = 0; - have_previous = false; if (strcmp(series, "packets") == 0) { if (_sample_count >= 1 && getSampleFromOldest(0, previous)) { for (size_t i = step; i < _sample_count && emitted < points; i += step, ++emitted) { - if (!getSampleFromOldest(i, sample)) { - break; - } - const int rx = sample.packets_recv >= previous.packets_recv - ? (int)(sample.packets_recv - previous.packets_recv) : 0; - const int tx = sample.packets_sent >= previous.packets_sent - ? (int)(sample.packets_sent - previous.packets_sent) : 0; - offset += snprintf(&buffer[offset], buffer_size - offset, - "%s[%lu,%d,%d]", - valid_emitted == 0 ? "" : ",", - static_cast(sample.uptime_secs), - rx, tx); - valid_emitted++; - if (offset + 40 >= buffer_size) { - break; + getSampleFromOldest(i, sample); + if (sample.uptime_secs > previous.uptime_secs) { + const uint32_t rx = sample.packets_recv - previous.packets_recv; + const uint32_t tx = sample.packets_sent - previous.packets_sent; + offset += snprintf(&buffer[offset], buffer_size - offset, + "%s[%lu,%d,%d]", + valid_emitted == 0 ? "" : ",", + static_cast(sample.uptime_secs), + static_cast(rx), static_cast(tx)); + valid_emitted++; + if (offset + 40 >= buffer_size) { + break; + } } previous = sample; } } } else { + have_previous = false; for (size_t i = 0; i < _sample_count && emitted < points; i += step, ++emitted) { if (!getSampleFromOldest(i, sample)) { break;