Skip to content

Commit 5d23a78

Browse files
cabana: de-Qt, part 2 (#38359)
1 parent 06a73f5 commit 5d23a78

20 files changed

Lines changed: 607 additions & 236 deletions

openpilot/tools/cabana/binaryview.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
#include <algorithm>
55

6-
#include <QDebug>
6+
#include <cstdio>
7+
78
#include <QFontDatabase>
89
#include <QHeaderView>
910
#include <QMouseEvent>
@@ -260,7 +261,8 @@ void BinaryViewModel::refresh() {
260261
int pos = sig->is_little_endian ? flipBitPos(sig->start_bit + j) : flipBitPos(sig->start_bit) + j;
261262
int idx = column_count * (pos / 8) + pos % 8;
262263
if (idx >= items.size()) {
263-
qWarning() << "signal " << sig->name.c_str() << "out of bounds.start_bit:" << sig->start_bit << "size:" << sig->size;
264+
fprintf(stderr, "signal %s out of bounds.start_bit: %d size: %d\n",
265+
sig->name.c_str(), sig->start_bit, sig->size);
264266
break;
265267
}
266268
if (j == 0) sig->is_little_endian ? items[idx].is_lsb = true : items[idx].is_msb = true;

openpilot/tools/cabana/cabana.cc

Lines changed: 140 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
#include <cstdio>
2+
#include <cstring>
3+
#include <memory>
4+
#include <string>
5+
16
#include <QApplication>
2-
#include <QCommandLineParser>
37

48
#include "tools/cabana/mainwin.h"
59
#include "tools/cabana/streams/devicestream.h"
@@ -9,6 +13,120 @@
913
#include "tools/cabana/streams/socketcanstream.h"
1014
#endif
1115

16+
namespace {
17+
18+
struct CabanaArgs {
19+
bool demo = false;
20+
bool auto_source = false;
21+
bool qcam = false;
22+
bool ecam = false;
23+
bool dcam = false;
24+
bool msgq = false;
25+
bool panda = false;
26+
bool no_vipc = false;
27+
std::string panda_serial;
28+
std::string socketcan;
29+
std::string zmq;
30+
std::string data_dir;
31+
std::string dbc;
32+
std::string route;
33+
};
34+
35+
void printUsage(const char *argv0) {
36+
fprintf(stderr,
37+
"Usage: %s [options] [route]\n"
38+
"\n"
39+
" route the drive to replay. find your drives at connect.comma.ai\n"
40+
"\n"
41+
"Options:\n"
42+
" --help show this help\n"
43+
" --demo use a demo route instead of providing your own\n"
44+
" --auto Auto load the route from the best available source (no video):\n"
45+
" internal, openpilotci, comma_api, car_segments, testing_closet\n"
46+
" --qcam load qcamera\n"
47+
" --ecam load wide road camera\n"
48+
" --dcam load driver camera\n"
49+
" --msgq read can messages from the msgq\n"
50+
" --panda read can messages from panda\n"
51+
" --panda-serial <serial> read can messages from panda with given serial\n"
52+
#ifdef __linux__
53+
" --socketcan <device> read can messages from given SocketCAN device\n"
54+
#endif
55+
" --zmq <ip-address> read can messages from zmq at the specified ip-address\n"
56+
" --data_dir <dir> local directory with routes\n"
57+
" --no-vipc do not output video\n"
58+
" --dbc <file> dbc file to open\n",
59+
argv0);
60+
}
61+
62+
// Returns true if value was consumed from argv[i+1].
63+
bool takeValue(int argc, char *argv[], int &i, std::string &out) {
64+
if (i + 1 >= argc) {
65+
fprintf(stderr, "error: %s requires a value\n", argv[i]);
66+
return false;
67+
}
68+
out = argv[++i];
69+
return true;
70+
}
71+
72+
// Returns 0 to continue, or a process exit code (0 for --help, 1 for errors).
73+
int parseArgs(int argc, char *argv[], CabanaArgs &args, bool &ok) {
74+
ok = false;
75+
for (int i = 1; i < argc; ++i) {
76+
const char *a = argv[i];
77+
if (std::strcmp(a, "--help") == 0 || std::strcmp(a, "-h") == 0) {
78+
printUsage(argv[0]);
79+
return 0;
80+
} else if (std::strcmp(a, "--demo") == 0) {
81+
args.demo = true;
82+
} else if (std::strcmp(a, "--auto") == 0) {
83+
args.auto_source = true;
84+
} else if (std::strcmp(a, "--qcam") == 0) {
85+
args.qcam = true;
86+
} else if (std::strcmp(a, "--ecam") == 0) {
87+
args.ecam = true;
88+
} else if (std::strcmp(a, "--dcam") == 0) {
89+
args.dcam = true;
90+
} else if (std::strcmp(a, "--msgq") == 0) {
91+
args.msgq = true;
92+
} else if (std::strcmp(a, "--panda") == 0) {
93+
args.panda = true;
94+
} else if (std::strcmp(a, "--panda-serial") == 0) {
95+
if (!takeValue(argc, argv, i, args.panda_serial)) return 1;
96+
args.panda = true;
97+
} else if (std::strcmp(a, "--socketcan") == 0) {
98+
if (!takeValue(argc, argv, i, args.socketcan)) return 1;
99+
#ifdef __linux__
100+
#else
101+
fprintf(stderr, "error: --socketcan is only supported on Linux\n");
102+
return 1;
103+
#endif
104+
} else if (std::strcmp(a, "--zmq") == 0) {
105+
if (!takeValue(argc, argv, i, args.zmq)) return 1;
106+
} else if (std::strcmp(a, "--data_dir") == 0) {
107+
if (!takeValue(argc, argv, i, args.data_dir)) return 1;
108+
} else if (std::strcmp(a, "--no-vipc") == 0) {
109+
args.no_vipc = true;
110+
} else if (std::strcmp(a, "--dbc") == 0) {
111+
if (!takeValue(argc, argv, i, args.dbc)) return 1;
112+
} else if (a[0] == '-') {
113+
fprintf(stderr, "error: unknown option %s\n", a);
114+
printUsage(argv[0]);
115+
return 1;
116+
} else if (args.route.empty()) {
117+
args.route = a;
118+
} else {
119+
fprintf(stderr, "error: unexpected argument %s\n", a);
120+
printUsage(argv[0]);
121+
return 1;
122+
}
123+
}
124+
ok = true;
125+
return 0;
126+
}
127+
128+
} // namespace
129+
12130
int main(int argc, char *argv[]) {
13131
QCoreApplication::setApplicationName("Cabana");
14132
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
@@ -20,69 +138,51 @@ int main(int argc, char *argv[]) {
20138
UnixSignalHandler signalHandler;
21139
utils::setTheme(settings.theme);
22140

23-
QCommandLineParser cmd_parser;
24-
cmd_parser.addHelpOption();
25-
cmd_parser.addPositionalArgument("route", "the drive to replay. find your drives at connect.comma.ai");
26-
cmd_parser.addOption({"demo", "use a demo route instead of providing your own"});
27-
cmd_parser.addOption({"auto", "Auto load the route from the best available source (no video): internal, openpilotci, comma_api, car_segments, testing_closet"});
28-
cmd_parser.addOption({"qcam", "load qcamera"});
29-
cmd_parser.addOption({"ecam", "load wide road camera"});
30-
cmd_parser.addOption({"dcam", "load driver camera"});
31-
cmd_parser.addOption({"msgq", "read can messages from the msgq"});
32-
cmd_parser.addOption({"panda", "read can messages from panda"});
33-
cmd_parser.addOption({"panda-serial", "read can messages from panda with given serial", "panda-serial"});
34-
#ifdef __linux__
35-
if (SocketCanStream::available()) {
36-
cmd_parser.addOption({"socketcan", "read can messages from given SocketCAN device", "socketcan"});
141+
CabanaArgs args;
142+
bool args_ok = false;
143+
if (const int code = parseArgs(argc, argv, args, args_ok); !args_ok) {
144+
return code;
37145
}
38-
#endif
39-
cmd_parser.addOption({"zmq", "read can messages from zmq at the specified ip-address", "ip-address"});
40-
cmd_parser.addOption({"data_dir", "local directory with routes", "data_dir"});
41-
cmd_parser.addOption({"no-vipc", "do not output video"});
42-
cmd_parser.addOption({"dbc", "dbc file to open", "dbc"});
43-
cmd_parser.process(app);
44146

45147
AbstractStream *stream = nullptr;
46148

47-
if (cmd_parser.isSet("msgq")) {
149+
if (args.msgq) {
48150
stream = new DeviceStream(&app);
49-
} else if (cmd_parser.isSet("zmq")) {
50-
stream = new DeviceStream(&app, cmd_parser.value("zmq"));
51-
} else if (cmd_parser.isSet("panda") || cmd_parser.isSet("panda-serial")) {
151+
} else if (!args.zmq.empty()) {
152+
stream = new DeviceStream(&app, QString::fromStdString(args.zmq));
153+
} else if (args.panda || !args.panda_serial.empty()) {
52154
try {
53-
stream = new PandaStream(&app, {.serial = cmd_parser.value("panda-serial").toStdString()});
155+
stream = new PandaStream(&app, {.serial = args.panda_serial});
54156
} catch (std::exception &e) {
55-
qWarning() << e.what();
157+
fprintf(stderr, "%s\n", e.what());
56158
return 0;
57159
}
58160
#ifdef __linux__
59-
} else if (SocketCanStream::available() && cmd_parser.isSet("socketcan")) {
60-
stream = new SocketCanStream(&app, {.device = cmd_parser.value("socketcan").toStdString()});
161+
} else if (SocketCanStream::available() && !args.socketcan.empty()) {
162+
stream = new SocketCanStream(&app, {.device = args.socketcan});
61163
#endif
62164
} else {
63165
uint32_t replay_flags = REPLAY_FLAG_NONE;
64-
if (cmd_parser.isSet("ecam")) replay_flags |= REPLAY_FLAG_ECAM;
65-
if (cmd_parser.isSet("qcam")) replay_flags |= REPLAY_FLAG_QCAMERA;
66-
if (cmd_parser.isSet("dcam")) replay_flags |= REPLAY_FLAG_DCAM;
67-
if (cmd_parser.isSet("no-vipc")) replay_flags |= REPLAY_FLAG_NO_VIPC;
166+
if (args.ecam) replay_flags |= REPLAY_FLAG_ECAM;
167+
if (args.qcam) replay_flags |= REPLAY_FLAG_QCAMERA;
168+
if (args.dcam) replay_flags |= REPLAY_FLAG_DCAM;
169+
if (args.no_vipc) replay_flags |= REPLAY_FLAG_NO_VIPC;
68170

69-
const QStringList args = cmd_parser.positionalArguments();
70171
QString route;
71-
if (args.size() > 0) {
72-
route = args.first();
73-
} else if (cmd_parser.isSet("demo")) {
172+
if (!args.route.empty()) {
173+
route = QString::fromStdString(args.route);
174+
} else if (args.demo) {
74175
route = DEMO_ROUTE;
75176
}
76177
if (!route.isEmpty()) {
77178
auto replay_stream = std::make_unique<ReplayStream>(&app);
78-
bool auto_source = cmd_parser.isSet("auto");
79-
if (!replay_stream->loadRoute(route.toStdString(), cmd_parser.value("data_dir").toStdString(), replay_flags, auto_source)) {
179+
if (!replay_stream->loadRoute(route.toStdString(), args.data_dir, replay_flags, args.auto_source)) {
80180
return 0;
81181
}
82182
stream = replay_stream.release();
83183
}
84184
}
85185

86-
MainWindow w(stream, cmd_parser.value("dbc"));
186+
MainWindow w(stream, QString::fromStdString(args.dbc));
87187
return app.exec();
88188
}

openpilot/tools/cabana/cameraview.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <GLES3/gl3.h>
77
#endif
88

9+
#include <cstdio>
10+
911
#include <QApplication>
1012

1113
namespace {
@@ -221,7 +223,8 @@ void CameraWidget::vipcThread() {
221223
while (!QThread::currentThread()->isInterruptionRequested()) {
222224
if (!vipc_client || cur_stream != requested_stream_type) {
223225
clearFrames();
224-
qDebug().nospace() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream;
226+
fprintf(stderr, "connecting to stream %d, was connected to %d\n",
227+
(int)requested_stream_type, (int)cur_stream);
225228
cur_stream = requested_stream_type;
226229
vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false));
227230
}

openpilot/tools/cabana/chart/chart.cc

Lines changed: 7 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,15 @@
33

44
#include <algorithm>
55
#include <limits>
6+
#include <random>
67

78
#include <QActionGroup>
89
#include <QApplication>
910
#include <QDrag>
1011
#include <QGraphicsLayout>
11-
#include <QGraphicsDropShadowEffect>
1212
#include <QGraphicsItemGroup>
13-
#include <QGraphicsOpacityEffect>
1413
#include <QMimeData>
1514
#include <QOpenGLWidget>
16-
#include <QPropertyAnimation>
17-
#include <QRandomGenerator>
1815
#include <QRubberBand>
1916
#include <QScreen>
2017
#include <QWindow>
@@ -421,45 +418,6 @@ qreal ChartView::niceNumber(qreal x, bool ceiling) {
421418
return q * z;
422419
}
423420

424-
QPixmap getBlankShadowPixmap(const QPixmap &px, int radius) {
425-
QGraphicsDropShadowEffect *e = new QGraphicsDropShadowEffect;
426-
e->setColor(QColor(40, 40, 40, 245));
427-
e->setOffset(0, 0);
428-
e->setBlurRadius(radius);
429-
430-
qreal dpr = px.devicePixelRatio();
431-
QPixmap blank(px.size());
432-
blank.setDevicePixelRatio(dpr);
433-
blank.fill(Qt::white);
434-
435-
QGraphicsScene scene;
436-
QGraphicsPixmapItem item(blank);
437-
item.setGraphicsEffect(e);
438-
scene.addItem(&item);
439-
440-
QPixmap shadow(px.size() + QSize(radius * dpr * 2, radius * dpr * 2));
441-
shadow.setDevicePixelRatio(dpr);
442-
shadow.fill(Qt::transparent);
443-
QPainter p(&shadow);
444-
scene.render(&p, {QPoint(), shadow.size() / dpr}, item.boundingRect().adjusted(-radius, -radius, radius, radius));
445-
return shadow;
446-
}
447-
448-
static QPixmap getDropPixmap(const QPixmap &src) {
449-
static QPixmap shadow_px;
450-
const int radius = 10;
451-
if (shadow_px.size() != src.size() + QSize(radius * 2, radius * 2)) {
452-
shadow_px = getBlankShadowPixmap(src, radius);
453-
}
454-
QPixmap px = shadow_px;
455-
QPainter p(&px);
456-
QRectF target_rect(QPointF(radius, radius), src.size() / src.devicePixelRatio());
457-
p.drawPixmap(target_rect.topLeft(), src);
458-
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
459-
p.fillRect(target_rect, QColor(0, 0, 0, 200));
460-
return px;
461-
}
462-
463421
void ChartView::contextMenuEvent(QContextMenuEvent *event) {
464422
QMenu context_menu(this);
465423
context_menu.addActions(menu->actions());
@@ -479,7 +437,7 @@ void ChartView::mousePressEvent(QMouseEvent *event) {
479437
charts_widget->stopAutoScroll();
480438
QDrag *drag = new QDrag(this);
481439
drag->setMimeData(mimeData);
482-
drag->setPixmap(getDropPixmap(px));
440+
drag->setPixmap(px);
483441
drag->setHotSpot(-QPoint(5, 5));
484442
drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::MoveAction);
485443
} else if (event->button() == Qt::LeftButton && QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) {
@@ -628,7 +586,6 @@ void ChartView::dropEvent(QDropEvent *event) {
628586
sigs.insert(sigs.end(), std::move_iterator(source_chart->sigs.begin()), std::move_iterator(source_chart->sigs.end()));
629587
updateAxisY();
630588
updateTitle();
631-
startAnimation();
632589

633590
source_chart->sigs.clear();
634591
charts_widget->removeChart(source_chart);
@@ -643,17 +600,6 @@ void ChartView::resetChartCache() {
643600
viewport()->update();
644601
}
645602

646-
void ChartView::startAnimation() {
647-
QGraphicsOpacityEffect *eff = new QGraphicsOpacityEffect(this);
648-
viewport()->setGraphicsEffect(eff);
649-
QPropertyAnimation *a = new QPropertyAnimation(eff, "opacity");
650-
a->setDuration(250);
651-
a->setStartValue(0.3);
652-
a->setEndValue(1);
653-
a->setEasingCurve(QEasingCurve::InBack);
654-
a->start(QPropertyAnimation::DeleteWhenStopped);
655-
}
656-
657603
void ChartView::paintEvent(QPaintEvent *event) {
658604
if (!can->liveStreaming()) {
659605
if (chart_pixmap.isNull()) {
@@ -822,9 +768,12 @@ void ChartView::setSeriesColor(QXYSeries *series, QColor color) {
822768
if (s != series && std::abs(color.hueF() - qobject_cast<QXYSeries *>(s)->color().hueF()) < 0.1) {
823769
// use different color to distinguish it from others.
824770
auto last_color = qobject_cast<QXYSeries *>(existing_series.back())->color();
771+
static thread_local std::mt19937 rng{std::random_device{}()};
772+
std::uniform_int_distribution<int> sat(35, 99);
773+
std::uniform_int_distribution<int> val(85, 99);
825774
color.setHsvF(std::fmod(last_color.hueF() + 60 / 360.0, 1.0),
826-
QRandomGenerator::global()->bounded(35, 100) / 100.0,
827-
QRandomGenerator::global()->bounded(85, 100) / 100.0);
775+
sat(rng) / 100.0,
776+
val(rng) / 100.0);
828777
break;
829778
}
830779
}

openpilot/tools/cabana/chart/chart.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ class ChartView : public QChartView {
3838
void updatePlotArea(int left, bool force = false);
3939
void showTip(double sec);
4040
void hideTip();
41-
void startAnimation();
4241
double secondsAtPoint(const QPointF &pt) const { return chart()->mapToValue(pt).x(); }
4342

4443
struct SigItem {

openpilot/tools/cabana/chart/chartswidget.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,6 @@ void ChartsContainer::dropEvent(QDropEvent *event) {
570570
charts_widget->updateLayout(true);
571571
charts_widget->updateTabBar();
572572
event->acceptProposedAction();
573-
chart->startAnimation();
574573
}
575574
drawDropIndicator({});
576575
}

0 commit comments

Comments
 (0)