mirror of https://github.com/commaai/openpilot.git
replay: refactor ConsoleUI to remove Qt dependency (#33826)
Refactor ConsoleUI to remove Qt dependency
This commit is contained in:
parent
30853a2c41
commit
371f60413a
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <QApplication>
|
||||
|
||||
#include "common/ratekeeper.h"
|
||||
#include "common/util.h"
|
||||
#include "common/version.h"
|
||||
|
||||
|
@ -57,7 +58,7 @@ void add_str(WINDOW *w, const char *str, Color color = Color::Default, bool bold
|
|||
|
||||
} // namespace
|
||||
|
||||
ConsoleUI::ConsoleUI(Replay *replay, QObject *parent) : replay(replay), sm({"carState", "liveParameters"}), QObject(parent) {
|
||||
ConsoleUI::ConsoleUI(Replay *replay) : replay(replay), sm({"carState", "liveParameters"}) {
|
||||
// Initialize curses
|
||||
initscr();
|
||||
clear();
|
||||
|
@ -80,24 +81,16 @@ ConsoleUI::ConsoleUI(Replay *replay, QObject *parent) : replay(replay), sm({"car
|
|||
|
||||
initWindows();
|
||||
|
||||
qRegisterMetaType<uint64_t>("uint64_t");
|
||||
qRegisterMetaType<ReplyMsgType>("ReplyMsgType");
|
||||
installMessageHandler([this](ReplyMsgType type, const std::string msg) {
|
||||
emit logMessageSignal(type, QString::fromStdString(msg));
|
||||
std::scoped_lock lock(mutex);
|
||||
logs.emplace_back(type, msg);
|
||||
});
|
||||
installDownloadProgressHandler([this](uint64_t cur, uint64_t total, bool success) {
|
||||
emit updateProgressBarSignal(cur, total, success);
|
||||
std::scoped_lock lock(mutex);
|
||||
progress_cur = cur;
|
||||
progress_total = total;
|
||||
download_success = success;
|
||||
});
|
||||
|
||||
QObject::connect(replay, &Replay::streamStarted, this, &ConsoleUI::updateSummary);
|
||||
QObject::connect(¬ifier, SIGNAL(activated(int)), SLOT(readyRead()));
|
||||
QObject::connect(this, &ConsoleUI::updateProgressBarSignal, this, &ConsoleUI::updateProgressBar);
|
||||
QObject::connect(this, &ConsoleUI::logMessageSignal, this, &ConsoleUI::logMessage);
|
||||
|
||||
sm_timer.callOnTimeout(this, &ConsoleUI::updateStatus);
|
||||
sm_timer.start(100);
|
||||
getch_timer.start(1000, this);
|
||||
readyRead();
|
||||
}
|
||||
|
||||
ConsoleUI::~ConsoleUI() {
|
||||
|
@ -136,9 +129,7 @@ void ConsoleUI::initWindows() {
|
|||
}
|
||||
}
|
||||
|
||||
void ConsoleUI::timerEvent(QTimerEvent *ev) {
|
||||
if (ev->timerId() != getch_timer.timerId()) return;
|
||||
|
||||
void ConsoleUI::updateSize() {
|
||||
if (is_term_resized(max_height, max_width)) {
|
||||
for (auto win : w) {
|
||||
if (win) delwin(win);
|
||||
|
@ -149,7 +140,6 @@ void ConsoleUI::timerEvent(QTimerEvent *ev) {
|
|||
initWindows();
|
||||
rWarning("resize term %dx%d", max_height, max_width);
|
||||
}
|
||||
updateTimeline();
|
||||
}
|
||||
|
||||
void ConsoleUI::updateStatus() {
|
||||
|
@ -169,12 +159,6 @@ void ConsoleUI::updateStatus() {
|
|||
|
||||
sm.update(0);
|
||||
|
||||
if (status != Status::Paused) {
|
||||
auto events = replay->events();
|
||||
uint64_t current_mono_time = replay->routeStartNanos() + replay->currentSeconds() * 1e9;
|
||||
bool playing = !events->empty() && events->back().mono_time > current_mono_time;
|
||||
status = playing ? Status::Playing : Status::Waiting;
|
||||
}
|
||||
auto [status_str, status_color] = status_text[status];
|
||||
write_item(0, 0, "STATUS: ", status_str, " ", false, status_color);
|
||||
std::string current_segment = " - " + std::to_string((int)(replay->currentSeconds() / 60));
|
||||
|
@ -218,7 +202,7 @@ void ConsoleUI::displayTimelineDesc() {
|
|||
}
|
||||
}
|
||||
|
||||
void ConsoleUI::logMessage(ReplyMsgType type, const QString &msg) {
|
||||
void ConsoleUI::logMessage(ReplyMsgType type, const std::string &msg) {
|
||||
if (auto win = w[Win::Log]) {
|
||||
Color color = Color::Default;
|
||||
if (type == ReplyMsgType::Debug) {
|
||||
|
@ -228,19 +212,19 @@ void ConsoleUI::logMessage(ReplyMsgType type, const QString &msg) {
|
|||
} else if (type == ReplyMsgType::Critical) {
|
||||
color = Color::Red;
|
||||
}
|
||||
add_str(win, qPrintable(msg + "\n"), color);
|
||||
add_str(win, (msg + "\n").c_str(), color);
|
||||
wrefresh(win);
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleUI::updateProgressBar(uint64_t cur, uint64_t total, bool success) {
|
||||
void ConsoleUI::updateProgressBar() {
|
||||
werase(w[Win::DownloadBar]);
|
||||
if (success && cur < total) {
|
||||
if (download_success && progress_cur < progress_total) {
|
||||
const int width = 35;
|
||||
const float progress = cur / (double)total;
|
||||
const float progress = progress_cur / (double)progress_total;
|
||||
const int pos = width * progress;
|
||||
wprintw(w[Win::DownloadBar], "Downloading [%s>%s] %d%% %s", std::string(pos, '=').c_str(),
|
||||
std::string(width - pos, ' ').c_str(), int(progress * 100.0), formattedDataSize(total).c_str());
|
||||
std::string(width - pos, ' ').c_str(), int(progress * 100.0), formattedDataSize(progress_total).c_str());
|
||||
}
|
||||
wrefresh(w[Win::DownloadBar]);
|
||||
}
|
||||
|
@ -288,16 +272,9 @@ void ConsoleUI::updateTimeline() {
|
|||
wrefresh(win);
|
||||
}
|
||||
|
||||
void ConsoleUI::readyRead() {
|
||||
int c;
|
||||
while ((c = getch()) != ERR) {
|
||||
handleKey(c);
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleUI::pauseReplay(bool pause) {
|
||||
replay->pause(pause);
|
||||
status = pause ? Status::Paused : Status::Waiting;
|
||||
status = pause ? Status::Paused : Status::Playing;
|
||||
}
|
||||
|
||||
void ConsoleUI::handleKey(char c) {
|
||||
|
@ -305,7 +282,6 @@ void ConsoleUI::handleKey(char c) {
|
|||
// pause the replay and blocking getchar()
|
||||
pauseReplay(true);
|
||||
updateStatus();
|
||||
getch_timer.stop();
|
||||
curs_set(true);
|
||||
nodelay(stdscr, false);
|
||||
|
||||
|
@ -330,7 +306,6 @@ void ConsoleUI::handleKey(char c) {
|
|||
nodelay(stdscr, true);
|
||||
curs_set(false);
|
||||
refresh();
|
||||
getch_timer.start(1000, this);
|
||||
|
||||
} else if (c == '+' || c == '=') {
|
||||
auto it = std::upper_bound(speed_array.begin(), speed_array.end(), replay->getSpeed());
|
||||
|
@ -367,7 +342,37 @@ void ConsoleUI::handleKey(char c) {
|
|||
replay->seekTo(-10, true);
|
||||
} else if (c == ' ') {
|
||||
pauseReplay(!replay->isPaused());
|
||||
} else if (c == 'q' || c == 'Q') {
|
||||
qApp->exit();
|
||||
}
|
||||
}
|
||||
|
||||
int ConsoleUI::exec() {
|
||||
RateKeeper rk("Replay", 20);
|
||||
while (true) {
|
||||
int c = getch();
|
||||
if (c == 'q' || c == 'Q') {
|
||||
break;
|
||||
}
|
||||
handleKey(c);
|
||||
|
||||
if (rk.frame() % 25) {
|
||||
updateSize();
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
updateTimeline();
|
||||
updateStatus();
|
||||
|
||||
{
|
||||
std::scoped_lock lock(mutex);
|
||||
updateProgressBar();
|
||||
for (auto &[type, msg] : logs) {
|
||||
logMessage(type, msg);
|
||||
}
|
||||
logs.clear();
|
||||
}
|
||||
|
||||
qApp->processEvents();
|
||||
rk.keepTime();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <QBasicTimer>
|
||||
#include <QObject>
|
||||
#include <QSocketNotifier>
|
||||
#include <QTimer>
|
||||
#include <QTimerEvent>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "tools/replay/replay.h"
|
||||
#include <ncurses.h>
|
||||
|
||||
class ConsoleUI : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
class ConsoleUI {
|
||||
public:
|
||||
ConsoleUI(Replay *replay, QObject *parent = 0);
|
||||
ConsoleUI(Replay *replay);
|
||||
~ConsoleUI();
|
||||
int exec();
|
||||
inline static const std::array speed_array = {0.2f, 0.5f, 1.0f, 2.0f, 3.0f};
|
||||
|
||||
private:
|
||||
|
@ -27,25 +23,21 @@ private:
|
|||
void updateSummary();
|
||||
void updateStatus();
|
||||
void pauseReplay(bool pause);
|
||||
void updateSize();
|
||||
void updateProgressBar();
|
||||
void logMessage(ReplyMsgType type, const std::string &msg);
|
||||
|
||||
enum Status { Waiting, Playing, Paused };
|
||||
enum Status { Playing, Paused };
|
||||
enum Win { Title, Stats, Log, LogBorder, DownloadBar, Timeline, TimelineDesc, Help, CarState, Max};
|
||||
std::array<WINDOW*, Win::Max> w{};
|
||||
SubMaster sm;
|
||||
Replay *replay;
|
||||
QBasicTimer getch_timer;
|
||||
QTimer sm_timer;
|
||||
QSocketNotifier notifier{0, QSocketNotifier::Read, this};
|
||||
int max_width, max_height;
|
||||
Status status = Status::Waiting;
|
||||
Status status = Status::Playing;
|
||||
|
||||
signals:
|
||||
void updateProgressBarSignal(uint64_t cur, uint64_t total, bool success);
|
||||
void logMessageSignal(ReplyMsgType type, const QString &msg);
|
||||
|
||||
private slots:
|
||||
void readyRead();
|
||||
void timerEvent(QTimerEvent *ev);
|
||||
void updateProgressBar(uint64_t cur, uint64_t total, bool success);
|
||||
void logMessage(ReplyMsgType type, const QString &msg);
|
||||
std::mutex mutex;
|
||||
std::vector<std::pair<ReplyMsgType, std::string>> logs;
|
||||
uint64_t progress_cur = 0;
|
||||
uint64_t progress_total = 0;
|
||||
bool download_success = false;
|
||||
};
|
||||
|
|
|
@ -151,5 +151,5 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
ConsoleUI console_ui(replay);
|
||||
replay->start(config.start_seconds);
|
||||
return app.exec();
|
||||
return console_ui.exec();
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ enum class FindFlag {
|
|||
|
||||
enum class TimelineType { None, Engaged, AlertInfo, AlertWarning, AlertCritical, UserFlag };
|
||||
typedef bool (*replayEventFilter)(const Event *, void *);
|
||||
typedef std::map<int, std::unique_ptr<Segment>> SegmentMap;
|
||||
Q_DECLARE_METATYPE(std::shared_ptr<LogReader>);
|
||||
|
||||
class Replay : public QObject {
|
||||
|
@ -82,8 +83,7 @@ public:
|
|||
inline double maxSeconds() const { return max_seconds_; }
|
||||
inline void setSpeed(float speed) { speed_ = speed; }
|
||||
inline float getSpeed() const { return speed_; }
|
||||
inline const std::vector<Event> *events() const { return &events_; }
|
||||
inline const std::map<int, std::unique_ptr<Segment>> &segments() const { return segments_; }
|
||||
inline const SegmentMap &segments() const { return segments_; }
|
||||
inline const std::string &carFingerprint() const { return car_fingerprint_; }
|
||||
inline const std::vector<std::tuple<double, double, TimelineType>> getTimeline() {
|
||||
std::lock_guard lk(timeline_lock);
|
||||
|
@ -102,7 +102,6 @@ protected slots:
|
|||
void segmentLoadFinished(bool success);
|
||||
|
||||
protected:
|
||||
typedef std::map<int, std::unique_ptr<Segment>> SegmentMap;
|
||||
std::optional<uint64_t> find(FindFlag flag);
|
||||
void pauseStreamThread();
|
||||
void startStream(const Segment *cur_segment);
|
||||
|
|
Loading…
Reference in New Issue