mirror of
https://github.com/infiniteCable2/openpilot.git
synced 2026-09-10 10:13:40 +08:00
cabana: de-QT streams (#38718)
This commit is contained in:
@@ -148,7 +148,7 @@ int main(int argc, char *argv[]) {
|
||||
if (args.msgq) {
|
||||
stream = new DeviceStream();
|
||||
} else if (!args.zmq.empty()) {
|
||||
stream = new DeviceStream(QString::fromStdString(args.zmq));
|
||||
stream = new DeviceStream(args.zmq);
|
||||
} else if (args.panda || !args.panda_serial.empty()) {
|
||||
try {
|
||||
stream = new PandaStream({.serial = args.panda_serial});
|
||||
@@ -175,6 +175,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
if (!route.isEmpty()) {
|
||||
auto replay_stream = std::make_unique<ReplayStream>();
|
||||
Connection err = replay_stream->error.connect([](const std::string &msg) { fprintf(stderr, "%s\n", msg.c_str()); });
|
||||
if (!replay_stream->loadRoute(route.toStdString(), args.data_dir, replay_flags, args.auto_source)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -358,6 +358,9 @@ void MainWindow::startStream(AbstractStream *stream, QString dbc_file) {
|
||||
delete video_splitter;
|
||||
|
||||
can = stream; // take ownership
|
||||
stream_connections_.push_back(can->error.connect([this](const std::string &msg) {
|
||||
QMessageBox::warning(this, tr("Error"), QString::fromStdString(msg));
|
||||
}));
|
||||
can->start();
|
||||
|
||||
loadFile(dbc_file);
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
Observable<const std::optional<std::pair<double, double>> &> timeRangeChanged;
|
||||
Observable<const MessageEventsMap &> eventsMerged;
|
||||
Observable<const std::set<MessageId> *, bool> msgsReceived;
|
||||
Observable<const std::string &> error;
|
||||
|
||||
SourceSet sources;
|
||||
|
||||
|
||||
@@ -9,17 +9,16 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "openpilot/cereal/services.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QMessageBox>
|
||||
#include "tools/cabana/utils/util.h"
|
||||
|
||||
// DeviceStream
|
||||
|
||||
DeviceStream::DeviceStream(QString address) : zmq_address(address) {
|
||||
DeviceStream::DeviceStream(std::string address) : zmq_address(std::move(address)) {
|
||||
}
|
||||
|
||||
DeviceStream::~DeviceStream() {
|
||||
@@ -46,19 +45,16 @@ void DeviceStream::stopBridge() {
|
||||
}
|
||||
|
||||
void DeviceStream::start() {
|
||||
if (!zmq_address.isEmpty()) {
|
||||
if (!zmq_address.empty()) {
|
||||
stopBridge();
|
||||
const std::string path = (std::filesystem::path(QCoreApplication::applicationDirPath().toStdString()) /
|
||||
"../../cereal/messaging/bridge").lexically_normal().string();
|
||||
const std::string addr = zmq_address.toStdString();
|
||||
const std::string path = (executableDir() / "../../cereal/messaging/bridge").lexically_normal().string();
|
||||
const char *can_filter = "/\"can/\"";
|
||||
|
||||
// Self-pipe: write end is CLOEXEC so it closes on successful exec. If exec
|
||||
// fails, the child writes errno and the parent aborts stream start.
|
||||
int err_pipe[2] = {-1, -1};
|
||||
if (::pipe(err_pipe) != 0) {
|
||||
QMessageBox::warning(nullptr, "Error",
|
||||
QString("Failed to start bridge: %1").arg(QString::fromLocal8Bit(strerror(errno))));
|
||||
error(std::string("Failed to start bridge: ") + strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -66,7 +62,7 @@ void DeviceStream::start() {
|
||||
if (pid == 0) {
|
||||
::close(err_pipe[0]);
|
||||
::fcntl(err_pipe[1], F_SETFD, FD_CLOEXEC);
|
||||
execl(path.c_str(), path.c_str(), addr.c_str(), can_filter, static_cast<char *>(nullptr));
|
||||
execl(path.c_str(), path.c_str(), zmq_address.c_str(), can_filter, static_cast<char *>(nullptr));
|
||||
const int err = errno;
|
||||
(void)!::write(err_pipe[1], &err, sizeof(err));
|
||||
_exit(127);
|
||||
@@ -75,8 +71,7 @@ void DeviceStream::start() {
|
||||
::close(err_pipe[1]);
|
||||
if (pid < 0) {
|
||||
::close(err_pipe[0]);
|
||||
QMessageBox::warning(nullptr, "Error",
|
||||
QString("Failed to start bridge: %1").arg(QString::fromLocal8Bit(strerror(errno))));
|
||||
error(std::string("Failed to start bridge: ") + strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,8 +82,7 @@ void DeviceStream::start() {
|
||||
// Child failed to exec; reap and surface the error.
|
||||
int status = 0;
|
||||
::waitpid(pid, &status, 0);
|
||||
QMessageBox::warning(nullptr, "Error",
|
||||
QString("Failed to start bridge: %1").arg(QString::fromLocal8Bit(strerror(exec_errno))));
|
||||
error(std::string("Failed to start bridge: ") + strerror(exec_errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -99,7 +93,7 @@ void DeviceStream::start() {
|
||||
}
|
||||
|
||||
void DeviceStream::streamThread() {
|
||||
zmq_address.isEmpty() ? unsetenv("ZMQ") : setenv("ZMQ", "1", 1);
|
||||
zmq_address.empty() ? unsetenv("ZMQ") : setenv("ZMQ", "1", 1);
|
||||
|
||||
std::unique_ptr<Context> context(Context::create());
|
||||
std::unique_ptr<SubSocket> sock(SubSocket::create(context.get(), "can", "127.0.0.1", false, true, services.at("can").queue_size));
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
|
||||
#include "tools/cabana/streams/livestream.h"
|
||||
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
|
||||
class DeviceStream : public LiveStream {
|
||||
public:
|
||||
DeviceStream(QString address = {});
|
||||
DeviceStream(std::string address = {});
|
||||
~DeviceStream();
|
||||
inline std::string routeName() const override {
|
||||
return "Live Streaming From " + (zmq_address.isEmpty() ? std::string("127.0.0.1") : zmq_address.toStdString());
|
||||
return "Live Streaming From " + (zmq_address.empty() ? std::string("127.0.0.1") : zmq_address);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -17,5 +18,5 @@ protected:
|
||||
void streamThread() override;
|
||||
void stopBridge();
|
||||
pid_t bridge_pid = -1;
|
||||
const QString zmq_address;
|
||||
const std::string zmq_address;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "tools/cabana/streams/replaystream.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <string>
|
||||
|
||||
#include "common/timing.h"
|
||||
#include "common/util.h"
|
||||
@@ -59,27 +59,25 @@ bool ReplayStream::loadRoute(const std::string &route, const std::string &data_d
|
||||
|
||||
bool success = replay->load();
|
||||
if (!success) {
|
||||
std::string message;
|
||||
if (replay->lastRouteError() == RouteLoadError::Unauthorized) {
|
||||
auto auth_content = util::read_file(util::getenv("HOME") + "/.comma/auth.json");
|
||||
QString message;
|
||||
if (auth_content.empty()) {
|
||||
message = "Authentication Required. Please run the following command to authenticate:\n\n"
|
||||
"python3 openpilot/tools/lib/auth.py\n\n"
|
||||
"This will grant access to routes from your comma account.";
|
||||
} else {
|
||||
message = QString("Access Denied. You do not have permission to access route:\n\n%1\n\n"
|
||||
"This is likely a private route.").arg(QString::fromStdString(route));
|
||||
message = "Access Denied. You do not have permission to access route:\n\n" + route + "\n\n"
|
||||
"This is likely a private route.";
|
||||
}
|
||||
QMessageBox::warning(nullptr, "Access Denied", message);
|
||||
} else if (replay->lastRouteError() == RouteLoadError::NetworkError) {
|
||||
QMessageBox::warning(nullptr, "Network Error",
|
||||
QString("Unable to load the route:\n\n %1.\n\nPlease check your network connection and try again.").arg(QString::fromStdString(route)));
|
||||
message = "Unable to load the route:\n\n " + route + ".\n\nPlease check your network connection and try again.";
|
||||
} else if (replay->lastRouteError() == RouteLoadError::FileNotFound) {
|
||||
QMessageBox::warning(nullptr, "Route Not Found",
|
||||
QString("The specified route could not be found:\n\n %1.\n\nPlease check the route name and try again.").arg(QString::fromStdString(route)));
|
||||
message = "The specified route could not be found:\n\n " + route + ".\n\nPlease check the route name and try again.";
|
||||
} else {
|
||||
QMessageBox::warning(nullptr, "Route Load Failed", QString("Failed to load route: '%1'").arg(QString::fromStdString(route)));
|
||||
message = "Failed to load route: '" + route + "'";
|
||||
}
|
||||
error(message);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@ AbstractStream *OpenReplayWidget::open() {
|
||||
QMessageBox::warning(nullptr, tr("Warning"), tr("Invalid route format: '%1'").arg(route));
|
||||
} else {
|
||||
auto replay_stream = std::make_unique<ReplayStream>();
|
||||
Connection err = replay_stream->error.connect([](const std::string &msg) {
|
||||
QMessageBox::warning(nullptr, tr("Error"), QString::fromStdString(msg));
|
||||
});
|
||||
uint32_t flags = REPLAY_FLAG_NONE;
|
||||
if (cameras[1]->isChecked()) flags |= REPLAY_FLAG_CABIN_CAMERA;
|
||||
if (cameras[2]->isChecked()) flags |= REPLAY_FLAG_WIDE_ROAD;
|
||||
@@ -211,7 +214,7 @@ OpenDeviceWidget::OpenDeviceWidget(QWidget *parent) : AbstractOpenStreamWidget(p
|
||||
}
|
||||
|
||||
AbstractStream *OpenDeviceWidget::open() {
|
||||
QString ip = ip_address->text().isEmpty() ? "127.0.0.1" : ip_address->text();
|
||||
std::string ip = ip_address->text().isEmpty() ? "127.0.0.1" : ip_address->text().toStdString();
|
||||
bool msgq = group->checkedId() == 0;
|
||||
return new DeviceStream(msgq ? "" : ip);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
#include <QColor>
|
||||
#include <QFontDatabase>
|
||||
@@ -454,27 +457,36 @@ void sigTermHandler(int s) {
|
||||
qApp->quit();
|
||||
}
|
||||
|
||||
std::filesystem::path executableDir() {
|
||||
#ifdef __APPLE__
|
||||
char buf[PATH_MAX];
|
||||
uint32_t size = sizeof(buf);
|
||||
if (_NSGetExecutablePath(buf, &size) != 0) return {};
|
||||
std::error_code ec;
|
||||
auto path = std::filesystem::canonical(buf, ec);
|
||||
return (ec ? std::filesystem::path(buf) : path).parent_path();
|
||||
#else
|
||||
return std::filesystem::path(util::readlink("/proc/self/exe")).parent_path();
|
||||
#endif
|
||||
}
|
||||
|
||||
void initApp(int argc, char *argv[], bool disable_hidpi) {
|
||||
// setup signal handlers to exit gracefully
|
||||
std::signal(SIGINT, sigTermHandler);
|
||||
std::signal(SIGTERM, sigTermHandler);
|
||||
|
||||
std::filesystem::path app_dir;
|
||||
#ifdef __APPLE__
|
||||
// Get the devicePixelRatio, and scale accordingly to maintain 1:1 rendering
|
||||
QApplication tmp(argc, argv);
|
||||
app_dir = QCoreApplication::applicationDirPath().toStdString();
|
||||
if (disable_hidpi) {
|
||||
qputenv("QT_SCALE_FACTOR", QString::number(1.0 / tmp.devicePixelRatio()).toLocal8Bit());
|
||||
}
|
||||
#else
|
||||
app_dir = std::filesystem::path(util::readlink("/proc/self/exe")).parent_path();
|
||||
#endif
|
||||
|
||||
qputenv("QT_DBL_CLICK_DIST", "150");
|
||||
// ensure the current dir matches the exectuable's directory
|
||||
std::error_code ec;
|
||||
std::filesystem::current_path(app_dir, ec);
|
||||
std::filesystem::current_path(executableDir(), ec);
|
||||
}
|
||||
|
||||
// embedded at build time from the bootstrap_icons package (see SConscript)
|
||||
|
||||
@@ -219,5 +219,6 @@ private:
|
||||
};
|
||||
|
||||
int num_decimals(double num);
|
||||
std::filesystem::path executableDir();
|
||||
void initApp(int argc, char *argv[], bool disable_hidpi = true);
|
||||
QPixmap bootstrapPixmap(const QString &id);
|
||||
|
||||
Reference in New Issue
Block a user