Say when a paused dashboard was frozen, so it cannot be mistaken for a hung one
This commit is contained in:
parent
e2bdc8debf
commit
575e3c590b
|
|
@ -3,6 +3,7 @@
|
||||||
#include "fgc/ui/IUserInterface.h"
|
#include "fgc/ui/IUserInterface.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -46,7 +47,15 @@ private:
|
||||||
std::atomic<bool> running_{false};
|
std::atomic<bool> running_{false};
|
||||||
// When set, the 100ms auto-redraw is suspended so the screen holds still and
|
// When set, the 100ms auto-redraw is suspended so the screen holds still and
|
||||||
// the operator can select/copy text (terminals drop a selection on repaint).
|
// the operator can select/copy text (terminals drop a selection on repaint).
|
||||||
|
// Display freeze (the `p` key), for selecting text out of the pane. While
|
||||||
|
// set, refreshLoop() stops posting redraws, so the frame on screen ages.
|
||||||
|
// paused_at_ is when it was frozen, so the badge can say how stale it is.
|
||||||
std::atomic<bool> paused_{false};
|
std::atomic<bool> paused_{false};
|
||||||
|
// Wall-clock time of the freeze, "HH:MM:SS", shown in the badge. Captured
|
||||||
|
// once: the badge must stay truthful WITHOUT a repaint, because repainting
|
||||||
|
// would pull the live snapshot and unfreeze what the pause is holding still.
|
||||||
|
std::string paused_at_hms_;
|
||||||
|
static std::string nowHms();
|
||||||
// True while the gimbal overlay is open, so the refresh loop can periodically
|
// True while the gimbal overlay is open, so the refresh loop can periodically
|
||||||
// re-pull a firmware dump (keeps the tracking counters ticking without 'd').
|
// re-pull a firmware dump (keeps the tracking counters ticking without 'd').
|
||||||
std::atomic<bool> gimbal_overlay_open_{false};
|
std::atomic<bool> gimbal_overlay_open_{false};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#include "fgc/ui/TuiUi.h"
|
#include "fgc/ui/TuiUi.h"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
#include "fgc/ChannelTopics.h"
|
#include "fgc/ChannelTopics.h"
|
||||||
|
|
||||||
#include "fgc/DumpParser.h"
|
#include "fgc/DumpParser.h"
|
||||||
|
|
@ -1247,13 +1249,30 @@ void TuiUi::pushLog(LogLevel level, const std::string& line) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wall-clock time the frame was frozen at, "HH:MM:SS". Captured once, because
|
||||||
|
// the badge must not need a repaint to stay truthful - repainting would unfreeze
|
||||||
|
// the very data the pause is holding still.
|
||||||
|
std::string TuiUi::nowHms() {
|
||||||
|
const auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||||
|
std::tm tm{};
|
||||||
|
localtime_r(&t, &tm);
|
||||||
|
char buf[16];
|
||||||
|
std::strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
void TuiUi::refreshLoop() {
|
void TuiUi::refreshLoop() {
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
auto last_dump = std::chrono::steady_clock::now();
|
auto last_dump = std::chrono::steady_clock::now();
|
||||||
while (running_) {
|
while (running_) {
|
||||||
std::this_thread::sleep_for(100ms);
|
std::this_thread::sleep_for(100ms);
|
||||||
if (!running_) break;
|
if (!running_) break;
|
||||||
if (paused_) continue; // frozen for text selection; don't repaint
|
// Frozen for text selection: do NOT repaint. Re-rendering would pull the
|
||||||
|
// live snapshot and the numbers would keep moving under the cursor,
|
||||||
|
// which is precisely what the freeze exists to prevent. The badge
|
||||||
|
// carries the wall-clock time of the freeze instead, so the frame says
|
||||||
|
// how old it is without having to be redrawn to say it.
|
||||||
|
if (paused_) continue;
|
||||||
// While the gimbal overlay is open, re-pull a firmware dump every ~3s so
|
// While the gimbal overlay is open, re-pull a firmware dump every ~3s so
|
||||||
// the encoder-tracking counters stay current without pressing 'd'.
|
// the encoder-tracking counters stay current without pressing 'd'.
|
||||||
if (gimbal_overlay_open_.load() && sink_ &&
|
if (gimbal_overlay_open_.load() && sink_ &&
|
||||||
|
|
@ -1332,7 +1351,15 @@ void TuiUi::uiLoop() {
|
||||||
text(" " + s.header.tower + " ") | bold,
|
text(" " + s.header.tower + " ") | bold,
|
||||||
text("build " + s.header.build) | dim,
|
text("build " + s.header.build) | dim,
|
||||||
filler(),
|
filler(),
|
||||||
(paused_ ? text(" PAUSED ") | color(Color::Black) | bgcolor(Color::Yellow) | bold
|
// A frozen frame has to say that it is frozen, and for how long.
|
||||||
|
// Without the age it is indistinguishable from a hung program: the
|
||||||
|
// numbers simply stop, which during a multi-minute home reads as a
|
||||||
|
// crash. Costing 15 minutes of "is it stuck?" is how this got added.
|
||||||
|
// Says WHEN it froze, not just that it is frozen. Without the time a
|
||||||
|
// held frame is indistinguishable from a hung program - the numbers
|
||||||
|
// simply stop - which during a multi-minute home reads as a crash.
|
||||||
|
(paused_ ? text(" PAUSED @" + paused_at_hms_ + " ")
|
||||||
|
| color(Color::Black) | bgcolor(Color::Yellow) | bold
|
||||||
: text("")),
|
: text("")),
|
||||||
text(" " + mode + " ") | (s.header.live ? color(Color::Green) : color(Color::Yellow)) | bold,
|
text(" " + mode + " ") | (s.header.live ? color(Color::Green) : color(Color::Yellow)) | bold,
|
||||||
text(" up " + std::to_string(s.header.uptime_ms / 1000) + "s ") | dim,
|
text(" up " + std::to_string(s.header.uptime_ms / 1000) + "s ") | dim,
|
||||||
|
|
@ -1649,6 +1676,7 @@ void TuiUi::uiLoop() {
|
||||||
}
|
}
|
||||||
if (c == "p") { // freeze/unfreeze the live refresh so text can be selected
|
if (c == "p") { // freeze/unfreeze the live refresh so text can be selected
|
||||||
paused_ = !paused_;
|
paused_ = !paused_;
|
||||||
|
if (paused_) paused_at_hms_ = nowHms();
|
||||||
return true; // this keypress redraws once so the indicator updates
|
return true; // this keypress redraws once so the indicator updates
|
||||||
}
|
}
|
||||||
if (overlay == Overlay::Help) { // vim-style section nav while help is open
|
if (overlay == Overlay::Help) { // vim-style section nav while help is open
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue