From 8e6efd2b008ce42fbceb09351e6a21fed85dd9b6 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 30 Oct 2026 21:27:46 +0100 Subject: [PATCH] Keep graph extrema readable and validate accepted packet counters --- tests/test_etcp_packet_link.c | 8 ++++---- tools/chatgui/src/call_audio_graphs.cpp | 17 ++++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/test_etcp_packet_link.c b/tests/test_etcp_packet_link.c index a2d3bbf5..d48d3cdb 100644 --- a/tests/test_etcp_packet_link.c +++ b/tests/test_etcp_packet_link.c @@ -73,11 +73,11 @@ int main(void) { /* Счётчик ETCP измеряет принятие драйвером, включая временную очередь UDP; отказ не считается. */ uint64_t sent_before = conn->diagnostic_wire_tx_bytes; - const uint8_t value = 42; first.blocked = 1; - assert(etcp_link_io_send(a, &value, 1) == 1 && conn->diagnostic_wire_tx_bytes == sent_before + 1); - assert(etcp_link_io_send(a, &value, 1) == -2 && conn->diagnostic_wire_tx_bytes == sent_before + 1); + const uint8_t value[8] = {42}; first.blocked = 1; + assert(etcp_link_io_send(a, value, sizeof(value)) == 8 && conn->diagnostic_wire_tx_bytes == sent_before + sizeof(value)); + assert(etcp_link_io_send(a, value, sizeof(value)) == -2 && conn->diagnostic_wire_tx_bytes == sent_before + sizeof(value)); first.blocked = 0; etcp_link_io_socket_writable(sock.fd, &sock); - assert(conn->diagnostic_wire_tx_bytes == sent_before + 1 && etcp_link_io_ready(a)); + assert(conn->diagnostic_wire_tx_bytes == sent_before + sizeof(value) && etcp_link_io_ready(a)); /* Подготовка не снимает ACK; отказ не меняет очередь/служебные признаки. */ b->initialized = b->link_status = 0; diff --git a/tools/chatgui/src/call_audio_graphs.cpp b/tools/chatgui/src/call_audio_graphs.cpp index 4befef1f..a31c191e 100644 --- a/tools/chatgui/src/call_audio_graphs.cpp +++ b/tools/chatgui/src/call_audio_graphs.cpp @@ -63,11 +63,12 @@ void CallAudioGraphs::paintEvent(QPaintEvent*) { double top = std::max(high, bottom + span) + span * .05; double y = 58 + index * row; p.setPen(foreground); p.drawText(QRectF(16, y, width() - 32, 20), title); - p.setPen(muted); p.drawText(QRectF(16, y + 20, width() - 32, 18), legend); - p.drawText(QRectF(16, y, width() - 32, 20), Qt::AlignRight, + p.setPen(muted); + p.drawText(QRectF(16, y + 20, width() - 32, 18), have ? text("Min: %1 · Max: %2 %3").arg(low / factor, 0, 'f', factor == 1 ? 0 : 1) .arg(high / factor, 0, 'f', factor == 1 ? 0 : 1).arg(unit) : text("No samples")); - QRectF box(62, y + 43, width() - 78, row - 66); + p.drawText(QRectF(16, y + 38, width() - 32, 32), Qt::TextWordWrap, legend); + QRectF box(62, y + 73, width() - 78, row - 96); auto px = [&](double time) { return box.left() + time / CALL_HISTORY_MS * box.width(); }; auto py = [&](double value) { return box.bottom() - (value - bottom) / (top - bottom) * box.height(); }; p.setPen(muted); p.drawText(QRectF(0, box.top(), 57, 16), Qt::AlignRight, QString::number(top / factor, 'f', factor == 1 ? 0 : 1)); @@ -85,6 +86,7 @@ void CallAudioGraphs::paintEvent(QPaintEvent*) { for (const auto& v : line.points) { QPointF pos(px(v.x), py(v.y)); if (!started || v.gap) path.moveTo(pos); else path.lineTo(pos); + if (v.gap) { p.setPen(Qt::NoPen); p.setBrush(line.color); p.drawEllipse(pos, 1.5, 1.5); p.setBrush(Qt::NoBrush); } started = true; } p.setPen(QPen(line.color, 1.5)); p.drawPath(path); @@ -97,7 +99,7 @@ void CallAudioGraphs::paintEvent(QPaintEvent*) { double x = xValue(v.at_ms); receive[0].points.push_back({x, (double)v.low_ms, gap}); receive[0].points.push_back({x, (double)v.high_ms, false}); receive[1].points.push_back({x, (double)v.reserve_ms, gap}); - if (v.missing_samples) { receive[2].points.push_back({x, (double)v.low_ms, true}); receive[2].points.push_back({x, (double)v.high_ms + 10, false}); } + if (v.missing_samples) receive[2].points.push_back({x, (double)v.low_ms, true}); } graph(0, text("Receive buffer"), text("Blue: buffer · Green: target · Red: missing audio"), receive, 100, text("ms"), {}, true); std::vector transmit{{blue, {}}, {orange, {}}, {violet, {}}}, rate{{green, {}}}; @@ -117,16 +119,17 @@ void CallAudioGraphs::paintEvent(QPaintEvent*) { rate, 256, text("B/s"), text("KiB/s"), false); double y = 58 + 3 * row; p.setPen(foreground); p.drawText(QRectF(16, y, width() - 32, 20), text("Receive buffer distribution")); - p.setPen(muted); p.drawText(QRectF(16, y + 20, width() - 32, 18), text("Time weighted · Older samples lose half their weight every 10 seconds")); + p.setPen(muted); p.drawText(QRectF(16, y + 38, width() - 32, 32), Qt::TextWordWrap, + text("Time weighted · Older samples lose half their weight every 10 seconds")); int first = 0, last = CALL_HISTORY_BINS - 1; while (first < last && m_data.histogram[first] == 0) ++first; while (last > first && m_data.histogram[last] == 0) --last; if (!m_data.observed_ms) first = 0, last = 1; if (first == last) { first = std::max(0, first - 1); last = std::min(CALL_HISTORY_BINS - 1, last + 1); } double maximum = 0; for (double v : m_data.histogram) maximum = std::max(maximum, v); - p.drawText(QRectF(16, y, width() - 32, 20), Qt::AlignRight, + p.drawText(QRectF(16, y + 20, width() - 32, 18), text("Min: %1 · Max: %2 %3").arg(0).arg(maximum * 100, 0, 'f', 1).arg("%")); - QRectF box(62, y + 43, width() - 78, row - 66); double scale = std::max(.05, maximum) * 1.05; + QRectF box(62, y + 73, width() - 78, row - 96); double scale = std::max(.05, maximum) * 1.05; double barWidth = box.width() / (last - first + 1); p.setPen(Qt::NoPen); p.setBrush(blue); for (int i = first; i <= last; ++i) { double h = m_data.histogram[i] / scale * box.height();