- Nightrider: lines 1px wider (3px outline), engagement border hidden, planner lines hidden when disengaged, stay on onroad view in park - Normal mode only: return to ready splash on park - Ready text sprite at native 1x size - Nice monitor: keeps claude processes at nice 19, runs every 30s Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
129 lines
4.0 KiB
C++
Executable File
129 lines
4.0 KiB
C++
Executable File
#include "selfdrive/ui/qt/ready.h"
|
|
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
|
|
#include <QPainter>
|
|
#include <QStackedLayout>
|
|
|
|
#include <QApplication>
|
|
#include <QGridLayout>
|
|
#include <QString>
|
|
#include <QTransform>
|
|
#include <QPixmap>
|
|
|
|
#include "common/params.h"
|
|
#include "common/timing.h"
|
|
|
|
#include "system/hardware/hw.h"
|
|
#include "selfdrive/ui/qt/qt_window.h"
|
|
#include "selfdrive/ui/qt/util.h"
|
|
|
|
|
|
ReadyWindow::ReadyWindow(QWidget *parent) : QWidget(parent) {
|
|
QGridLayout *layout = new QGridLayout(this);
|
|
layout->setSpacing(0);
|
|
layout->setMargin(0);
|
|
|
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
|
setStyleSheet("ReadyWindow { background-color: black; }");
|
|
|
|
timer = new QTimer(this);
|
|
timer->callOnTimeout(this, &ReadyWindow::refresh);
|
|
uptime.start();
|
|
}
|
|
|
|
void ReadyWindow::showEvent(QShowEvent *event) {
|
|
refresh();
|
|
timer->start(2 * 1000);
|
|
}
|
|
|
|
void ReadyWindow::hideEvent(QHideEvent *event) {
|
|
timer->stop();
|
|
}
|
|
|
|
void ReadyWindow::paintEvent(QPaintEvent *event) {
|
|
QPainter painter(this);
|
|
painter.fillRect(rect(), Qt::black);
|
|
|
|
if (is_hot) {
|
|
if (img_hot.isNull()) {
|
|
img_hot.load("/data/openpilot/selfdrive/clearpilot/theme/clearpilot/images/hot.png");
|
|
}
|
|
int x = (width() - img_hot.width()) / 2;
|
|
int y = (height() - img_hot.height()) / 2;
|
|
painter.drawPixmap(x, y, img_hot);
|
|
} else {
|
|
// Boot logo — same rotation as spinner (bg.jpg is pre-rotated 90° CW for framebuffer)
|
|
if (img_bg.isNull()) {
|
|
QPixmap raw("/usr/comma/bg.jpg");
|
|
if (!raw.isNull()) {
|
|
QTransform rot;
|
|
rot.rotate(-90);
|
|
img_bg = raw.transformed(rot);
|
|
}
|
|
}
|
|
if (!img_bg.isNull()) {
|
|
QPixmap scaled = img_bg.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
int x = (width() - scaled.width()) / 2;
|
|
int y = (height() - scaled.height()) / 2;
|
|
painter.drawPixmap(x, y, scaled);
|
|
}
|
|
|
|
if (error_msg.isEmpty()) {
|
|
// "READY!" 8-bit text sprite, 2x size, 15% below center
|
|
static QPixmap ready_text("/data/openpilot/selfdrive/clearpilot/theme/clearpilot/images/ready_text.png");
|
|
if (!ready_text.isNull()) {
|
|
int tx = (width() - ready_text.width()) / 2;
|
|
int ty = height() / 2 + height() * 15 / 100;
|
|
painter.drawPixmap(tx, ty, ready_text);
|
|
}
|
|
} else {
|
|
// Error state: red text at 25% below center
|
|
QFont font("Inter", 50, QFont::Bold);
|
|
painter.setFont(font);
|
|
painter.setPen(QColor(0xFF, 0x44, 0x44));
|
|
int ty = height() / 2 + height() * 25 / 100;
|
|
QRect text_rect(0, ty, width(), 100);
|
|
painter.drawText(text_rect, Qt::AlignHCenter | Qt::AlignTop, error_msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReadyWindow::refresh() {
|
|
bool changed = false;
|
|
|
|
// Temperature check
|
|
std::string bytes = params.get("Offroad_TemperatureTooHigh");
|
|
bool was_hot = is_hot;
|
|
if (!bytes.empty()) {
|
|
auto doc = QJsonDocument::fromJson(bytes.data());
|
|
is_hot = true;
|
|
cur_temp = doc["extra"].toString();
|
|
} else {
|
|
is_hot = false;
|
|
}
|
|
if (is_hot != was_hot) changed = true;
|
|
|
|
// Error state checks (only when not hot — hot has its own display)
|
|
if (!is_hot) {
|
|
QString prev_error = error_msg;
|
|
|
|
// Panda check — same logic as sidebar, with 10s grace period on startup
|
|
if (uptime.elapsed() > 10000 &&
|
|
uiState()->scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
|
|
error_msg = "PANDA NOT CONNECTED";
|
|
}
|
|
// Car unrecognized check
|
|
else if (!params.get("Offroad_CarUnrecognized").empty()) {
|
|
error_msg = "CAR NOT RECOGNIZED";
|
|
}
|
|
else {
|
|
error_msg = "";
|
|
}
|
|
|
|
if (error_msg != prev_error) changed = true;
|
|
}
|
|
|
|
if (changed) update();
|
|
} |