Fire Firehose

This commit is contained in:
whoisdomi
2026-06-01 08:19:45 -05:00
committed by firestar5683
parent 45060a07b7
commit 6eb513501d
19 changed files with 17 additions and 837 deletions
-1
View File
@@ -11,7 +11,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"AlwaysAllowUploads", {PERSISTENT, BOOL, "0"}},
{"AlwaysOnDM", {PERSISTENT, BOOL}},
{"ApiCache_Device", {PERSISTENT, STRING}},
{"ApiCache_FirehoseStats", {PERSISTENT, JSON}},
{"AssistNowToken", {PERSISTENT, STRING}},
{"AthenadPid", {PERSISTENT, INT}},
{"AthenadUploadQueue", {PERSISTENT, JSON}},
+2 -2
View File
@@ -133,8 +133,8 @@ class TestParams:
def test_params_get_type(self):
# json
self.params.put("ApiCache_FirehoseStats", {"a": 0})
assert self.params.get("ApiCache_FirehoseStats") == {"a": 0}
self.params.put("ApiCache_DriveStats", {"a": 0})
assert self.params.get("ApiCache_DriveStats") == {"a": 0}
# int
self.params.put("BootCount", 1441)
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

+2 -2
View File
@@ -23,7 +23,7 @@ if arch == "Darwin":
qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"]
qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs)
widgets_src = ["qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/prime_state.cc",
widgets_src = ["qt/widgets/input.cc", "qt/prime_state.cc",
"qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc",
"qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc",
"qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc",
@@ -39,7 +39,7 @@ qt_libs = [widgets, qt_util] + base_libs
qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc",
"qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc",
"qt/offroad/software_settings.cc", "qt/offroad/developer_panel.cc", "qt/offroad/onboarding.cc",
"qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", "qt/offroad/firehose.cc",
"qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc",
"qt/onroad/onroad_home.cc", "qt/onroad/annotated_camera.cc", "qt/onroad/model.cc",
"qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc"]
-1
View File
@@ -54,7 +54,6 @@ class MainLayout(Widget):
self._sidebar.set_callbacks(on_settings=self._on_settings_clicked,
on_flag=self._on_bookmark_clicked,
open_settings=lambda: self.open_settings(PanelType.TOGGLES))
self._layouts[MainState.HOME]._setup_widget.set_open_settings_callback(lambda: self.open_settings(PanelType.FIREHOSE))
self._layouts[MainState.HOME].set_settings_callback(lambda: self.open_settings(PanelType.TOGGLES))
self._layouts[MainState.SETTINGS].set_callbacks(on_close=self._set_mode_for_state)
self._layouts[MainState.ONROAD].set_click_callback(self._on_onroad_clicked)
-90
View File
@@ -1,90 +0,0 @@
import pyray as rl
from openpilot.system.ui.lib.application import gui_app, FontWeight, FONT_SCALE
from openpilot.system.ui.lib.multilang import tr, trn, tr_noop
from openpilot.system.ui.lib.text_measure import measure_text_cached
from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel
from openpilot.system.ui.lib.wrap_text import wrap_text
from openpilot.selfdrive.ui.mici.layouts.settings.firehose import FirehoseLayoutBase
TITLE = tr_noop("Firehose Mode")
DESCRIPTION = tr_noop(
"openpilot learns to drive by watching humans, like you, drive.\n\n"
+ "Firehose Mode allows you to maximize your training data uploads to improve "
+ "openpilot's driving models. More data means bigger models, which means better Experimental Mode."
)
INSTRUCTIONS = tr_noop(
"For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.\n\n"
+ "Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.\n\n\n"
+ "Frequently Asked Questions\n\n"
+ "Does it matter how or where I drive? Nope, just drive as you normally would.\n\n"
+ "Do all of my segments get pulled in Firehose Mode? No, we selectively pull a subset of your segments.\n\n"
+ "What's a good USB-C adapter? Any fast phone or laptop charger should be fine.\n\n"
+ "Does it matter which software I run? Yes, only upstream openpilot (and particular forks) are able to be used for training."
)
class FirehoseLayout(FirehoseLayoutBase):
def __init__(self):
super().__init__()
self._scroll_panel = GuiScrollPanel()
def _render(self, rect: rl.Rectangle):
# Calculate content dimensions
content_rect = rl.Rectangle(rect.x, rect.y, rect.width, self._content_height)
# Handle scrolling and render with clipping
scroll_offset = self._scroll_panel.update(rect, content_rect)
rl.begin_scissor_mode(int(rect.x), int(rect.y), int(rect.width), int(rect.height))
self._content_height = self._render_content(rect, scroll_offset)
rl.end_scissor_mode()
def _render_content(self, rect: rl.Rectangle, scroll_offset: float) -> int:
x = int(rect.x + 40)
y = int(rect.y + 40 + scroll_offset)
w = int(rect.width - 80)
# Title (centered)
title_text = tr(TITLE) # live translate
title_font = gui_app.font(FontWeight.MEDIUM)
text_width = measure_text_cached(title_font, title_text, 100).x
title_x = rect.x + (rect.width - text_width) / 2
rl.draw_text_ex(title_font, title_text, rl.Vector2(round(title_x), round(y)), 100, 0, rl.WHITE)
y += 200
# Description
y = self._draw_wrapped_text(x, y, w, tr(DESCRIPTION), gui_app.font(FontWeight.NORMAL), 45, rl.WHITE)
y += 40 + 20
# Separator
rl.draw_rectangle(x, y, w, 2, self.GRAY)
y += 30 + 20
# Status
status_text, status_color = self._get_status()
y = self._draw_wrapped_text(x, y, w, status_text, gui_app.font(FontWeight.BOLD), 60, status_color)
y += 20 + 20
# Contribution count (if available)
if self._segment_count > 0:
contrib_text = trn("{} segment of your driving is in the training dataset so far.",
"{} segments of your driving is in the training dataset so far.", self._segment_count).format(self._segment_count)
y = self._draw_wrapped_text(x, y, w, contrib_text, gui_app.font(FontWeight.BOLD), 52, rl.WHITE)
y += 20 + 20
# Separator
rl.draw_rectangle(x, y, w, 2, self.GRAY)
y += 30 + 20
# Instructions
y = self._draw_wrapped_text(x, y, w, tr(INSTRUCTIONS), gui_app.font(FontWeight.NORMAL), 40, self.LIGHT_GRAY)
# bottom margin + remove effect of scroll offset
return int(round(y - self._scroll_panel.offset + 40))
def _draw_wrapped_text(self, x, y, width, text, font, font_size, color):
wrapped = wrap_text(font, text, font_size, width)
for line in wrapped:
rl.draw_text_ex(font, line, rl.Vector2(round(x), round(y)), font_size, 0, color)
y += font_size * FONT_SCALE
return round(y)
+1 -7
View File
@@ -4,7 +4,6 @@ from enum import IntEnum
from collections.abc import Callable
from openpilot.selfdrive.ui.layouts.settings.developer import DeveloperLayout
from openpilot.selfdrive.ui.layouts.settings.device import DeviceLayout
from openpilot.selfdrive.ui.layouts.settings.firehose import FirehoseLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.main_panel import StarPilotLayout
from openpilot.selfdrive.ui.layouts.settings.software import SoftwareLayout
from openpilot.selfdrive.ui.layouts.settings.toggles import TogglesLayout
@@ -37,8 +36,7 @@ class PanelType(IntEnum):
NETWORK = 2
TOGGLES = 3
SOFTWARE = 4
FIREHOSE = 5
DEVELOPER = 6
DEVELOPER = 5
@dataclass
@@ -67,7 +65,6 @@ class SettingsLayout(Widget):
PanelType.NETWORK: PanelInfo(tr_noop("Network"), NetworkUI(wifi_manager)),
PanelType.TOGGLES: PanelInfo(tr_noop("Toggles"), TogglesLayout()),
PanelType.SOFTWARE: PanelInfo(tr_noop("Software"), SoftwareLayout()),
PanelType.FIREHOSE: PanelInfo(tr_noop("Firehose"), FirehoseLayout()),
PanelType.DEVELOPER: PanelInfo(tr_noop("Developer"), DeveloperLayout()),
}
@@ -143,9 +140,6 @@ class SettingsLayout(Widget):
# Navigation buttons
y = rect.y + 300
for panel_type, panel_info in self._panels.items():
if panel_type == PanelType.FIREHOSE:
continue
button_rect = rl.Rectangle(rect.x + 50, y, rect.width - 150, NAV_BTN_HEIGHT)
# Button styling
@@ -1,222 +0,0 @@
import requests
import threading
import time
import pyray as rl
from openpilot.common.api import api_get
from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.ui.lib.api_helpers import get_token
from openpilot.selfdrive.ui.ui_state import ui_state, device
from openpilot.system.athena.registration import UNREGISTERED_DONGLE_ID
from openpilot.system.ui.lib.application import gui_app, FontWeight, FONT_SCALE
from openpilot.system.ui.lib.wrap_text import wrap_text
from openpilot.system.ui.lib.scroll_panel2 import GuiScrollPanel2
from openpilot.system.ui.lib.multilang import tr, trn, tr_noop
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.scroller import NavRawScrollPanel
TITLE = tr_noop("Firehose Mode")
DESCRIPTION = tr_noop(
"openpilot learns to drive by watching humans, like you, drive.\n\n"
+ "Firehose Mode allows you to maximize your training data uploads to improve "
+ "openpilot's driving models. More data means bigger models, which means better Experimental Mode."
)
INSTRUCTIONS_INTRO = tr_noop(
"For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.\n\n"
+ "Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card."
)
FAQ_HEADER = tr_noop("Frequently Asked Questions")
FAQ_ITEMS = [
(tr_noop("Does it matter how or where I drive?"), tr_noop("Nope, just drive as you normally would.")),
(tr_noop("Do all of my segments get pulled in Firehose Mode?"), tr_noop("No, we selectively pull a subset of your segments.")),
(tr_noop("What's a good USB-C adapter?"), tr_noop("Any fast phone or laptop charger should be fine.")),
(tr_noop("Does it matter which software I run?"), tr_noop("Yes, only upstream openpilot (and particular forks) are able to be used for training.")),
]
class FirehoseLayoutBase(Widget):
PARAM_KEY = "ApiCache_FirehoseStats"
GREEN = rl.Color(46, 204, 113, 255)
RED = rl.Color(231, 76, 60, 255)
GRAY = rl.Color(68, 68, 68, 255)
LIGHT_GRAY = rl.Color(228, 228, 228, 255)
UPDATE_INTERVAL = 30 # seconds
def __init__(self):
super().__init__()
self._params = Params()
self._session = requests.Session() # reuse session to reduce SSL handshake overhead
self._segment_count = self._get_segment_count()
self._scroll_panel = GuiScrollPanel2(horizontal=False)
self._content_height = 0
self._running = True
self._update_thread = threading.Thread(target=self._update_loop, daemon=True)
self._update_thread.start()
def __del__(self):
self._running = False
try:
if self._update_thread and self._update_thread.is_alive():
self._update_thread.join(timeout=1.0)
except Exception:
pass
def show_event(self):
super().show_event()
self._scroll_panel.set_offset(0)
def _get_segment_count(self) -> int:
stats = self._params.get(self.PARAM_KEY)
if not stats:
return 0
try:
return int(stats.get("firehose", 0))
except Exception:
cloudlog.exception(f"Failed to decode firehose stats: {stats}")
return 0
def _render(self, rect: rl.Rectangle):
# compute total content height for scrolling
content_height = self._measure_content_height(rect)
scroll_offset = self._scroll_panel.update(rect, content_height)
# start drawing with offset
x = rect.x + 40
y = rect.y + 40 + scroll_offset
w = rect.width - 80
# Title
title_text = tr(TITLE)
title_font = gui_app.font(FontWeight.BOLD)
title_size = 64
rl.draw_text_ex(title_font, title_text, rl.Vector2(x, y), title_size, 0, rl.WHITE)
y += int(title_size * FONT_SCALE) + 20
# Description
y = self._draw_wrapped_text(x, y, w, tr(DESCRIPTION), gui_app.font(FontWeight.ROMAN), 36, rl.WHITE)
y += 20
# Separator
rl.draw_rectangle_rec(rl.Rectangle(x, y, w, 2), self.GRAY)
y += 20
# Status
status_text, status_color = self._get_status()
y = self._draw_wrapped_text(x, y, w, status_text, gui_app.font(FontWeight.BOLD), 48, status_color)
y += 20
# Contribution count (if available)
if self._segment_count > 0:
contrib_text = trn("{} segment of your driving is in the training dataset so far.",
"{} segments of your driving is in the training dataset so far.", self._segment_count).format(self._segment_count)
y = self._draw_wrapped_text(x, y, w, contrib_text, gui_app.font(FontWeight.BOLD), 42, rl.WHITE)
y += 20
# Separator
rl.draw_rectangle_rec(rl.Rectangle(x, y, w, 2), self.GRAY)
y += 20
# Instructions intro
y = self._draw_wrapped_text(x, y, w, tr(INSTRUCTIONS_INTRO), gui_app.font(FontWeight.ROMAN), 32, self.LIGHT_GRAY)
y += 20
# FAQ Header
y = self._draw_wrapped_text(x, y, w, tr(FAQ_HEADER), gui_app.font(FontWeight.BOLD), 44, rl.WHITE)
y += 20
# FAQ Items
for question, answer in FAQ_ITEMS:
y = self._draw_wrapped_text(x, y, w, tr(question), gui_app.font(FontWeight.BOLD), 32, self.LIGHT_GRAY)
y = self._draw_wrapped_text(x, y, w, tr(answer), gui_app.font(FontWeight.ROMAN), 32, self.LIGHT_GRAY)
y += 20
def _draw_wrapped_text(self, x, y, width, text, font, font_size, color):
wrapped = wrap_text(font, text, font_size, width)
for line in wrapped:
rl.draw_text_ex(font, line, rl.Vector2(x, y), font_size, 0, color)
y += int(font_size * FONT_SCALE)
return y
def _measure_content_height(self, rect: rl.Rectangle) -> int:
# Rough measurement using the same wrapping as rendering
w = int(rect.width - 80)
y = 40
# Title
title_size = 72
y += int(title_size * FONT_SCALE) + 20
# Description
desc_lines = wrap_text(gui_app.font(FontWeight.ROMAN), tr(DESCRIPTION), 36, w)
y += int(len(desc_lines) * 36 * FONT_SCALE) + 20
# Separator + Status
y += 2 + 20
status_text, _ = self._get_status()
status_lines = wrap_text(gui_app.font(FontWeight.BOLD), status_text, 48, w)
y += int(len(status_lines) * 48 * FONT_SCALE) + 20
# Contribution count
if self._segment_count > 0:
contrib_text = trn("{} segment of your driving is in the training dataset so far.",
"{} segments of your driving is in the training dataset so far.", self._segment_count).format(self._segment_count)
contrib_lines = wrap_text(gui_app.font(FontWeight.BOLD), contrib_text, 42, w)
y += int(len(contrib_lines) * 42 * FONT_SCALE) + 20
# Separator + Instructions
y += 2 + 20
# Instructions intro
intro_lines = wrap_text(gui_app.font(FontWeight.ROMAN), tr(INSTRUCTIONS_INTRO), 32, w)
y += int(len(intro_lines) * 32 * FONT_SCALE) + 20
# FAQ Header
faq_header_lines = wrap_text(gui_app.font(FontWeight.BOLD), tr(FAQ_HEADER), 44, w)
y += int(len(faq_header_lines) * 44 * FONT_SCALE) + 20
# FAQ Items
for question, answer in FAQ_ITEMS:
q_lines = wrap_text(gui_app.font(FontWeight.BOLD), tr(question), 32, w)
y += int(len(q_lines) * 32 * FONT_SCALE)
a_lines = wrap_text(gui_app.font(FontWeight.ROMAN), tr(answer), 32, w)
y += int(len(a_lines) * 32 * FONT_SCALE) + 20
# bottom padding
y += 40
return y
def _get_status(self) -> tuple[str, rl.Color]:
network_type = ui_state.sm["deviceState"].networkType
network_metered = ui_state.sm["deviceState"].networkMetered
if not network_metered and network_type != 0: # Not metered and connected
return tr("ACTIVE"), self.GREEN
else:
return tr("INACTIVE: connect to an unmetered network"), self.RED
def _fetch_firehose_stats(self):
try:
dongle_id = self._params.get("DongleId")
if not dongle_id or dongle_id == UNREGISTERED_DONGLE_ID:
return
identity_token = get_token(dongle_id)
response = api_get(f"v1/devices/{dongle_id}/firehose_stats", access_token=identity_token, session=self._session)
if response.status_code == 200:
data = response.json()
self._segment_count = data.get("firehose", 0)
self._params.put(self.PARAM_KEY, data)
except Exception as e:
cloudlog.error(f"Failed to fetch firehose stats: {e}")
def _update_loop(self):
while self._running:
if not ui_state.started and device._awake:
self._fetch_firehose_stats()
time.sleep(self.UPDATE_INTERVAL)
class FirehoseLayout(NavRawScrollPanel, FirehoseLayoutBase):
pass
-112
View File
@@ -1,112 +0,0 @@
#include "selfdrive/ui/qt/offroad/firehose.h"
#include "selfdrive/ui/ui.h"
#include "selfdrive/ui/qt/offroad/settings.h"
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFrame>
#include <QScrollArea>
#include <QStackedLayout>
#include <QProgressBar>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTimer>
FirehosePanel::FirehosePanel(SettingsWindow *parent) : QWidget((QWidget*)parent) {
layout = new QVBoxLayout(this);
layout->setContentsMargins(40, 40, 40, 40);
layout->setSpacing(20);
// header
QLabel *title = new QLabel(tr("Firehose Mode"));
title->setStyleSheet("font-size: 100px; font-weight: 500; font-family: 'Noto Color Emoji';");
layout->addWidget(title, 0, Qt::AlignCenter);
// Create a container for the content
QFrame *content = new QFrame();
content->setStyleSheet("background-color: #292929; border-radius: 15px; padding: 20px;");
QVBoxLayout *content_layout = new QVBoxLayout(content);
content_layout->setSpacing(20);
// Top description
QLabel *description = new QLabel(tr("openpilot learns to drive by watching humans, like you, drive.\n\nFirehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode."));
description->setStyleSheet("font-size: 45px; padding-bottom: 20px;");
description->setWordWrap(true);
content_layout->addWidget(description);
// Add a separator
QFrame *line = new QFrame();
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
line->setStyleSheet("background-color: #444444; margin-top: 5px; margin-bottom: 5px;");
content_layout->addWidget(line);
toggle_label = new QLabel(tr("Firehose Mode: ACTIVE"));
toggle_label->setStyleSheet("font-size: 60px; font-weight: bold; color: white;");
content_layout->addWidget(toggle_label);
// Add contribution label
contribution_label = new QLabel();
contribution_label->setStyleSheet("font-size: 52px; margin-top: 10px; margin-bottom: 10px;");
contribution_label->setWordWrap(true);
contribution_label->hide();
content_layout->addWidget(contribution_label);
// Add a separator before detailed instructions
QFrame *line2 = new QFrame();
line2->setFrameShape(QFrame::HLine);
line2->setFrameShadow(QFrame::Sunken);
line2->setStyleSheet("background-color: #444444; margin-top: 10px; margin-bottom: 10px;");
content_layout->addWidget(line2);
// Detailed instructions at the bottom
detailed_instructions = new QLabel(tr(
"For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br>"
"<br>"
"Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br>"
"<br><br>"
"<b>Frequently Asked Questions</b><br><br>"
"<i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br>"
"<i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br>"
"<i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br>"
"<i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training."
));
detailed_instructions->setStyleSheet("font-size: 40px; color: #E4E4E4;");
detailed_instructions->setWordWrap(true);
content_layout->addWidget(detailed_instructions);
layout->addWidget(content, 1);
// Set up the API request for firehose stats
const QString dongle_id = QString::fromStdString(Params().get("DongleId"));
firehose_stats = new RequestRepeater(this, CommaApi::BASE_URL + "/v1/devices/" + dongle_id + "/firehose_stats",
"ApiCache_FirehoseStats", 30, false);
QObject::connect(firehose_stats, &RequestRepeater::requestDone, [=](const QString &response, bool success) {
if (success) {
QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
QJsonObject json = doc.object();
int count = json["firehose"].toInt();
contribution_label->setText(tr("<b>%n segment(s)</b> of your driving is in the training dataset so far.", "", count));
contribution_label->show();
}
});
QObject::connect(uiState(), &UIState::uiUpdate, this, &FirehosePanel::refresh);
}
void FirehosePanel::refresh() {
auto deviceState = (*uiState()->sm)["deviceState"].getDeviceState();
auto networkType = deviceState.getNetworkType();
bool networkMetered = deviceState.getNetworkMetered();
bool is_active = !networkMetered && (networkType != cereal::DeviceState::NetworkType::NONE);
if (is_active) {
toggle_label->setText(tr("ACTIVE"));
toggle_label->setStyleSheet("font-size: 60px; font-weight: bold; color: #2ecc71;");
} else {
toggle_label->setText(tr("<span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network"));
toggle_label->setStyleSheet("font-size: 60px;");
}
}
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#include <QWidget>
#include <QVBoxLayout>
#include <QLabel>
#include "selfdrive/ui/qt/request_repeater.h"
// Forward declarations
class SettingsWindow;
class FirehosePanel : public QWidget {
Q_OBJECT
public:
explicit FirehosePanel(SettingsWindow *parent);
private:
QVBoxLayout *layout;
QLabel *detailed_instructions;
QLabel *contribution_label;
QLabel *toggle_label;
RequestRepeater *firehose_stats;
private slots:
void refresh();
};
-118
View File
@@ -1,118 +0,0 @@
/****************************************************************************
** Meta object code from reading C++ file 'firehose.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.8)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include "firehose.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'firehose.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.12.8. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
QT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_FirehosePanel_t {
QByteArrayData data[3];
char stringdata0[23];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_FirehosePanel_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_FirehosePanel_t qt_meta_stringdata_FirehosePanel = {
{
QT_MOC_LITERAL(0, 0, 13), // "FirehosePanel"
QT_MOC_LITERAL(1, 14, 7), // "refresh"
QT_MOC_LITERAL(2, 22, 0) // ""
},
"FirehosePanel\0refresh\0"
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_FirehosePanel[] = {
// content:
8, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: name, argc, parameters, tag, flags
1, 0, 19, 2, 0x08 /* Private */,
// slots: parameters
QMetaType::Void,
0 // eod
};
void FirehosePanel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
auto *_t = static_cast<FirehosePanel *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->refresh(); break;
default: ;
}
}
Q_UNUSED(_a);
}
QT_INIT_METAOBJECT const QMetaObject FirehosePanel::staticMetaObject = { {
&QWidget::staticMetaObject,
qt_meta_stringdata_FirehosePanel.data,
qt_meta_data_FirehosePanel,
qt_static_metacall,
nullptr,
nullptr
} };
const QMetaObject *FirehosePanel::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *FirehosePanel::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_FirehosePanel.stringdata0))
return static_cast<void*>(this);
return QWidget::qt_metacast(_clname);
}
int FirehosePanel::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 1)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 1;
}
return _id;
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE
-1
View File
@@ -20,7 +20,6 @@
#include "selfdrive/ui/qt/widgets/prime.h"
#include "selfdrive/ui/qt/widgets/scrollview.h"
#include "selfdrive/ui/qt/offroad/developer_panel.h"
#include "selfdrive/ui/qt/offroad/firehose.h"
#include "starpilot/ui/qt/offroad/starpilot_settings.h"
-3
View File
@@ -141,6 +141,3 @@ private:
Params params;
ParamWatcher *fs_watch;
};
// Forward declaration
class FirehosePanel;
-142
View File
@@ -1,142 +0,0 @@
/****************************************************************************
** Meta object code from reading C++ file 'wifi.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.8)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include "wifi.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'wifi.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.12.8. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
QT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_WiFiPromptWidget_t {
QByteArrayData data[5];
char stringdata0[43];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_WiFiPromptWidget_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_WiFiPromptWidget_t qt_meta_stringdata_WiFiPromptWidget = {
{
QT_MOC_LITERAL(0, 0, 16), // "WiFiPromptWidget"
QT_MOC_LITERAL(1, 17, 12), // "openSettings"
QT_MOC_LITERAL(2, 30, 0), // ""
QT_MOC_LITERAL(3, 31, 5), // "index"
QT_MOC_LITERAL(4, 37, 5) // "param"
},
"WiFiPromptWidget\0openSettings\0\0index\0"
"param"
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_WiFiPromptWidget[] = {
// content:
8, // revision
0, // classname
0, 0, // classinfo
3, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
3, // signalCount
// signals: name, argc, parameters, tag, flags
1, 2, 29, 2, 0x06 /* Public */,
1, 1, 34, 2, 0x26 /* Public | MethodCloned */,
1, 0, 37, 2, 0x26 /* Public | MethodCloned */,
// signals: parameters
QMetaType::Void, QMetaType::Int, QMetaType::QString, 3, 4,
QMetaType::Void, QMetaType::Int, 3,
QMetaType::Void,
0 // eod
};
void WiFiPromptWidget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
auto *_t = static_cast<WiFiPromptWidget *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->openSettings((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< const QString(*)>(_a[2]))); break;
case 1: _t->openSettings((*reinterpret_cast< int(*)>(_a[1]))); break;
case 2: _t->openSettings(); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (WiFiPromptWidget::*)(int , const QString & );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&WiFiPromptWidget::openSettings)) {
*result = 0;
return;
}
}
}
}
QT_INIT_METAOBJECT const QMetaObject WiFiPromptWidget::staticMetaObject = { {
&QFrame::staticMetaObject,
qt_meta_stringdata_WiFiPromptWidget.data,
qt_meta_data_WiFiPromptWidget,
qt_static_metacall,
nullptr,
nullptr
} };
const QMetaObject *WiFiPromptWidget::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *WiFiPromptWidget::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_WiFiPromptWidget.stringdata0))
return static_cast<void*>(this);
return QFrame::qt_metacast(_clname);
}
int WiFiPromptWidget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QFrame::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 3)
qt_static_metacall(this, _c, _id, _a);
_id -= 3;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 3)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 3;
}
return _id;
}
// SIGNAL 0
void WiFiPromptWidget::openSettings(int _t1, const QString & _t2)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE
-5
View File
@@ -14,7 +14,6 @@
#include "selfdrive/ui/qt/request_repeater.h"
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/qt_window.h"
#include "selfdrive/ui/qt/widgets/wifi.h"
using qrcodegen::QrCode;
@@ -232,10 +231,6 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) {
QVBoxLayout *content_layout = new QVBoxLayout(content);
content_layout->setContentsMargins(0, 0, 0, 0);
content_layout->setSpacing(30);
WiFiPromptWidget *wifi_prompt = new WiFiPromptWidget;
QObject::connect(wifi_prompt, &WiFiPromptWidget::openSettings, this, &SetupWidget::openSettings);
content_layout->addWidget(wifi_prompt);
content_layout->addStretch();
mainLayout->addWidget(content);
-45
View File
@@ -1,45 +0,0 @@
#include "selfdrive/ui/qt/widgets/wifi.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QPixmap>
#include <QPushButton>
WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) {
// Setup Firehose Mode
QVBoxLayout *main_layout = new QVBoxLayout(this);
main_layout->setContentsMargins(56, 40, 56, 40);
main_layout->setSpacing(42);
QLabel *title = new QLabel(tr("<span style='font-family: \"Noto Color Emoji\";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span>"));
title->setStyleSheet("font-size: 64px; font-weight: 500;");
main_layout->addWidget(title);
QLabel *desc = new QLabel(tr("Maximize your training data uploads to improve openpilot's driving models."));
desc->setStyleSheet("font-size: 40px; font-weight: 400;");
desc->setWordWrap(true);
main_layout->addWidget(desc);
QPushButton *settings_btn = new QPushButton(tr("Open"));
connect(settings_btn, &QPushButton::clicked, [=]() { emit openSettings(1, "FirehosePanel"); });
settings_btn->setStyleSheet(R"(
QPushButton {
font-size: 48px;
font-weight: 500;
border-radius: 10px;
background-color: #465BEA;
padding: 32px;
}
QPushButton:pressed {
background-color: #3049F4;
}
)");
main_layout->addWidget(settings_btn);
setStyleSheet(R"(
WiFiPromptWidget {
background-color: #333333;
border-radius: 10px;
}
)");
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include <QFrame>
#include <QWidget>
class WiFiPromptWidget : public QFrame {
Q_OBJECT
public:
explicit WiFiPromptWidget(QWidget* parent = 0);
signals:
void openSettings(int index = 0, const QString &param = "");
};
@@ -103,11 +103,6 @@ def setup_settings_software_branch_switcher(click, pm: PubMaster):
click(1984, 449)
def setup_settings_firehose(click, pm: PubMaster):
setup_settings(click, pm)
click(278, 845)
def setup_settings_developer(click, pm: PubMaster):
CP = car.CarParams()
CP.alphaLongitudinalAvailable = True # show alpha long control toggle
@@ -226,7 +221,6 @@ CASES = {
"settings_software_download": setup_settings_software_download,
"settings_software_release_notes": setup_settings_software_release_notes,
"settings_software_branch_switcher": setup_settings_software_branch_switcher,
"settings_firehose": setup_settings_firehose,
"settings_developer": setup_settings_developer,
"keyboard": setup_keyboard,
"pair_device": setup_pair_device,
+12 -39
View File
@@ -8,27 +8,24 @@ from openpilot.system.ui.lib.wrap_text import wrap_text
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.confirm_dialog import alert_dialog
from openpilot.system.ui.widgets.button import Button, ButtonStyle
from openpilot.system.ui.widgets.label import Label
LOGO_WIDTH = 750
LOGO_HEIGHT = 770
class SetupWidget(Widget):
def __init__(self):
super().__init__()
self._open_settings_callback = None
self._pairing_dialog: PairingDialog | None = None
self._pair_device_btn = Button(lambda: tr("Pair device"), self._show_pairing, button_style=ButtonStyle.PRIMARY)
self._open_settings_btn = Button(lambda: tr("Open"), lambda: self._open_settings_callback() if self._open_settings_callback else None,
button_style=ButtonStyle.PRIMARY)
self._firehose_label = Label(lambda: tr("🔥 Firehose Mode 🔥"), font_weight=FontWeight.MEDIUM, font_size=64)
def set_open_settings_callback(self, callback):
self._open_settings_callback = callback
self._logo_texture = gui_app.texture("images/StarPilotLogo.png", LOGO_WIDTH, LOGO_HEIGHT)
def _render(self, rect: rl.Rectangle):
if not ui_state.prime_state.is_paired():
self._render_registration(rect)
else:
self._render_firehose_prompt(rect)
self._render_logo(rect)
def _render_registration(self, rect: rl.Rectangle):
"""Render registration prompt."""
@@ -55,36 +52,12 @@ class SetupWidget(Widget):
button_rect = rl.Rectangle(x, y + 30, w, 200)
self._pair_device_btn.render(button_rect)
def _render_firehose_prompt(self, rect: rl.Rectangle):
"""Render firehose prompt widget."""
rl.draw_rectangle_rounded(rl.Rectangle(rect.x, rect.y, rect.width, 500), 0.04, 20, rl.Color(51, 51, 51, 255))
# Content margins (56, 40, 56, 40)
x = rect.x + 56
y = rect.y + 40
w = rect.width - 112
spacing = 42
# Title with fire emojis
self._firehose_label.render(rl.Rectangle(rect.x, y, rect.width, 64))
y += 64 + spacing
# Description
desc_font = gui_app.font(FontWeight.NORMAL)
desc_text = tr("Maximize your training data uploads to improve openpilot's driving models.")
wrapped_desc = wrap_text(desc_font, desc_text, 40, int(w))
for line in wrapped_desc:
rl.draw_text_ex(desc_font, line, rl.Vector2(x, y), 40, 0, rl.WHITE)
y += 40 * FONT_SCALE
y += spacing
# Open button
button_height = 48 + 64 # font size + padding
button_rect = rl.Rectangle(x, y, w, button_height)
self._open_settings_btn.render(button_rect)
def _render_logo(self, rect: rl.Rectangle):
tex_w = self._logo_texture.width
tex_h = self._logo_texture.height
x = rect.x + (rect.width - tex_w) / 2
y = rect.y + (rect.height - tex_h) / 2
rl.draw_texture(self._logo_texture, int(x), int(y), rl.WHITE)
def _show_pairing(self):
if not system_time_valid():