Qt onroad alerts (#20776)
parent
00aa20f55a
commit
f907219957
|
@ -13,13 +13,14 @@ from selfdrive.controls.lib.alertmanager import AlertManager
|
|||
|
||||
EventName = car.CarEvent.EventName
|
||||
|
||||
def cycle_alerts(duration=200, is_metric=False):
|
||||
def cycle_alerts(duration=2000, is_metric=False):
|
||||
alerts = list(EVENTS.keys())
|
||||
print(alerts)
|
||||
|
||||
alerts = [EventName.preDriverDistracted, EventName.promptDriverDistracted, EventName.driverDistracted]
|
||||
#alerts = [EventName.preDriverDistracted, EventName.promptDriverDistracted, EventName.driverDistracted]
|
||||
alerts = [EventName.preLaneChangeLeft, EventName.preLaneChangeRight]
|
||||
|
||||
CP = CarInterface.get_params("HONDA CIVIC 2016 TOURING")
|
||||
CP = CarInterface.get_params("HONDA CIVIC 2016")
|
||||
sm = messaging.SubMaster(['deviceState', 'pandaState', 'roadCameraState', 'modelV2', 'liveCalibration',
|
||||
'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman'])
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ if arch == "Darwin":
|
|||
del base_libs[base_libs.index('OpenCL')]
|
||||
qt_env['FRAMEWORKS'] += ['OpenCL']
|
||||
|
||||
widgets_src = ["qt/widgets/input.cc", "qt/widgets/drive_stats.cc", "qt/sound.cc",
|
||||
widgets_src = ["qt/widgets/input.cc", "qt/widgets/drive_stats.cc",
|
||||
"qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc",
|
||||
"qt/widgets/offroad_alerts.cc", "qt/widgets/setup.cc", "qt/widgets/keyboard.cc",
|
||||
"qt/widgets/scrollview.cc", "#phonelibs/qrcode/QrCode.cc", "qt/api.cc",
|
||||
|
|
|
@ -293,54 +293,6 @@ static void ui_draw_vision_header(UIState *s) {
|
|||
ui_draw_vision_event(s);
|
||||
}
|
||||
|
||||
static void ui_draw_vision_footer(UIState *s) {
|
||||
ui_draw_vision_face(s);
|
||||
}
|
||||
|
||||
static float get_alert_alpha(float blink_rate) {
|
||||
return 0.375 * cos((millis_since_boot() / 1000) * 2 * M_PI * blink_rate) + 0.625;
|
||||
}
|
||||
|
||||
static void ui_draw_vision_alert(UIState *s) {
|
||||
static std::map<cereal::ControlsState::AlertSize, const int> alert_size_map = {
|
||||
{cereal::ControlsState::AlertSize::SMALL, 241},
|
||||
{cereal::ControlsState::AlertSize::MID, 390},
|
||||
{cereal::ControlsState::AlertSize::FULL, s->fb_h}};
|
||||
const UIScene *scene = &s->scene;
|
||||
bool longAlert1 = scene->alert_text1.length() > 15;
|
||||
|
||||
NVGcolor color = bg_colors[s->status];
|
||||
color.a *= get_alert_alpha(scene->alert_blinking_rate);
|
||||
const int alr_h = alert_size_map[scene->alert_size] + bdr_s;
|
||||
const Rect rect = {.x = s->viz_rect.x - bdr_s,
|
||||
.y = s->fb_h - alr_h,
|
||||
.w = s->viz_rect.w + (bdr_s * 2),
|
||||
.h = alr_h};
|
||||
|
||||
ui_fill_rect(s->vg, rect, color);
|
||||
ui_fill_rect(s->vg, rect, nvgLinearGradient(s->vg, rect.x, rect.y, rect.x, rect.bottom(),
|
||||
nvgRGBAf(0.0, 0.0, 0.0, 0.05), nvgRGBAf(0.0, 0.0, 0.0, 0.35)));
|
||||
|
||||
nvgFillColor(s->vg, COLOR_WHITE);
|
||||
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE);
|
||||
|
||||
if (scene->alert_size == cereal::ControlsState::AlertSize::SMALL) {
|
||||
ui_draw_text(s, rect.centerX(), rect.centerY() + 15, scene->alert_text1.c_str(), 40*2.5, COLOR_WHITE, "sans-semibold");
|
||||
} else if (scene->alert_size == cereal::ControlsState::AlertSize::MID) {
|
||||
ui_draw_text(s, rect.centerX(), rect.centerY() - 45, scene->alert_text1.c_str(), 48*2.5, COLOR_WHITE, "sans-bold");
|
||||
ui_draw_text(s, rect.centerX(), rect.centerY() + 75, scene->alert_text2.c_str(), 36*2.5, COLOR_WHITE, "sans-regular");
|
||||
} else if (scene->alert_size == cereal::ControlsState::AlertSize::FULL) {
|
||||
nvgFontSize(s->vg, (longAlert1?72:96)*2.5);
|
||||
nvgFontFace(s->vg, "sans-bold");
|
||||
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
||||
nvgTextBox(s->vg, rect.x, rect.y+(longAlert1?360:420), rect.w-60, scene->alert_text1.c_str(), NULL);
|
||||
nvgFontSize(s->vg, 48*2.5);
|
||||
nvgFontFace(s->vg, "sans-regular");
|
||||
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BOTTOM);
|
||||
nvgTextBox(s->vg, rect.x, rect.h-(longAlert1?300:360), rect.w-60, scene->alert_text2.c_str(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_draw_vision_frame(UIState *s) {
|
||||
// Draw video frames
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
@ -361,8 +313,8 @@ static void ui_draw_vision(UIState *s) {
|
|||
}
|
||||
// Set Speed, Current Speed, Status/Events
|
||||
ui_draw_vision_header(s);
|
||||
if (scene->alert_size == cereal::ControlsState::AlertSize::NONE) {
|
||||
ui_draw_vision_footer(s);
|
||||
if (s->scene.controls_state.getAlertSize() == cereal::ControlsState::AlertSize::NONE) {
|
||||
ui_draw_vision_face(s);
|
||||
}
|
||||
} else {
|
||||
ui_draw_driver_view(s);
|
||||
|
@ -378,8 +330,7 @@ static void ui_draw_background(UIState *s) {
|
|||
void ui_draw(UIState *s, int w, int h) {
|
||||
s->viz_rect = Rect{bdr_s, bdr_s, w - 2 * bdr_s, h - 2 * bdr_s};
|
||||
|
||||
const bool draw_alerts = s->scene.started;
|
||||
const bool draw_vision = draw_alerts && s->vipc_client->connected;
|
||||
const bool draw_vision = s->scene.started && s->vipc_client->connected;
|
||||
|
||||
// GL drawing functions
|
||||
ui_draw_background(s);
|
||||
|
@ -397,10 +348,6 @@ void ui_draw(UIState *s, int w, int h) {
|
|||
ui_draw_vision(s);
|
||||
}
|
||||
|
||||
if (draw_alerts && s->scene.alert_size != cereal::ControlsState::AlertSize::NONE) {
|
||||
ui_draw_vision_alert(s);
|
||||
}
|
||||
|
||||
if (s->scene.driver_view && !s->vipc_client->connected) {
|
||||
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
||||
ui_draw_text(s, s->viz_rect.centerX(), s->viz_rect.centerY(), "Please wait for camera to start", 40 * 2.5, COLOR_WHITE, "sans-bold");
|
||||
|
|
|
@ -30,6 +30,7 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
|
|||
onroad = new OnroadWindow(this);
|
||||
slayout->addWidget(onroad);
|
||||
QObject::connect(this, &HomeWindow::update, onroad, &OnroadWindow::update);
|
||||
QObject::connect(this, &HomeWindow::offroadTransitionSignal, onroad, &OnroadWindow::offroadTransition);
|
||||
|
||||
home = new OffroadHome();
|
||||
slayout->addWidget(home);
|
||||
|
@ -56,7 +57,7 @@ void HomeWindow::mousePressEvent(QMouseEvent* e) {
|
|||
}
|
||||
|
||||
// Handle sidebar collapsing
|
||||
if (childAt(e->pos()) == onroad) {
|
||||
if (onroad->isVisible() && (!sidebar->isVisible() || e->x() > sidebar->width())) {
|
||||
sidebar->setVisible(!sidebar->isVisible());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ signals:
|
|||
// forwarded signals
|
||||
void displayPowerChanged(bool on);
|
||||
void update(const UIState &s);
|
||||
void offroadTransitionSignal(bool offroad);
|
||||
|
||||
public slots:
|
||||
void offroadTransition(bool offroad);
|
||||
|
|
|
@ -1,17 +1,179 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "common/timing.h"
|
||||
#include "common/swaglog.h"
|
||||
#include "selfdrive/common/timing.h"
|
||||
#include "selfdrive/common/swaglog.h"
|
||||
#include "selfdrive/ui/qt/onroad.h"
|
||||
#include "selfdrive/ui/paint.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
|
||||
#include "onroad.h"
|
||||
#include "paint.h"
|
||||
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
|
||||
layout = new QStackedLayout();
|
||||
layout->setStackingMode(QStackedLayout::StackAll);
|
||||
|
||||
OnroadWindow::~OnroadWindow() {
|
||||
// old UI on bottom
|
||||
nvg = new NvgWindow(this);
|
||||
layout->addWidget(nvg);
|
||||
QObject::connect(this, &OnroadWindow::update, nvg, &NvgWindow::update);
|
||||
|
||||
alerts = new OnroadAlerts(this);
|
||||
QObject::connect(this, &OnroadWindow::update, alerts, &OnroadAlerts::update);
|
||||
QObject::connect(this, &OnroadWindow::offroadTransition, alerts, &OnroadAlerts::offroadTransition);
|
||||
|
||||
// hack to align the onroad alerts, better way to do this?
|
||||
QVBoxLayout *alerts_container = new QVBoxLayout(this);
|
||||
alerts_container->setMargin(0);
|
||||
alerts_container->addStretch(1);
|
||||
alerts_container->addWidget(alerts, 0, Qt::AlignBottom);
|
||||
QWidget *w = new QWidget(this);
|
||||
w->setLayout(alerts_container);
|
||||
|
||||
layout->addWidget(w);
|
||||
|
||||
// alerts on top
|
||||
layout->setCurrentWidget(w);
|
||||
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
// ***** onroad widgets *****
|
||||
|
||||
OnroadAlerts::OnroadAlerts(QWidget *parent) : QFrame(parent) {
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setSpacing(40);
|
||||
layout->setMargin(20);
|
||||
|
||||
title = new QLabel();
|
||||
title->setWordWrap(true);
|
||||
title->setAlignment(Qt::AlignCenter);
|
||||
layout->addWidget(title);
|
||||
|
||||
msg = new QLabel();
|
||||
msg->setWordWrap(true);
|
||||
msg->setAlignment(Qt::AlignCenter);
|
||||
layout->addWidget(msg);
|
||||
|
||||
layout->addStretch(1);
|
||||
layout->insertStretch(0, 1);
|
||||
|
||||
setLayout(layout);
|
||||
setStyleSheet("color: white;");
|
||||
setVisible(false);
|
||||
|
||||
// setup sounds
|
||||
for (auto &kv : sound_map) {
|
||||
auto path = QUrl::fromLocalFile(kv.second.first);
|
||||
sounds[kv.first].setSource(path);
|
||||
}
|
||||
}
|
||||
|
||||
void OnroadAlerts::update(const UIState &s) {
|
||||
SubMaster &sm = *(s.sm);
|
||||
if (sm.updated("carState")) {
|
||||
// scale volume with speed
|
||||
volume = util::map_val(sm["carState"].getCarState().getVEgo(), 0.f, 20.f,
|
||||
Hardware::MIN_VOLUME, Hardware::MAX_VOLUME);
|
||||
}
|
||||
if (sm.updated("controlsState")) {
|
||||
const cereal::ControlsState::Reader &cs = sm["controlsState"].getControlsState();
|
||||
updateAlert(QString::fromStdString(cs.getAlertText1()), QString::fromStdString(cs.getAlertText2()),
|
||||
cs.getAlertBlinkingRate(), cs.getAlertType(), cs.getAlertSize(), cs.getAlertSound());
|
||||
} else {
|
||||
// Handle controls timeout
|
||||
if (s.scene.deviceState.getStarted() && (sm.frame - s.scene.started_frame) > 10 * UI_FREQ) {
|
||||
const uint64_t cs_frame = sm.rcv_frame("controlsState");
|
||||
if (cs_frame < s.scene.started_frame) {
|
||||
// car is started, but controlsState hasn't been seen at all
|
||||
updateAlert("openpilot Unavailable", "Waiting for controls to start", 0,
|
||||
"controlsWaiting", cereal::ControlsState::AlertSize::MID, AudibleAlert::NONE);
|
||||
} else if ((sm.frame - cs_frame) > 5 * UI_FREQ) {
|
||||
// car is started, but controls is lagging or died
|
||||
updateAlert("TAKE CONTROL IMMEDIATELY", "Controls Unresponsive", 0,
|
||||
"controlsUnresponsive", cereal::ControlsState::AlertSize::FULL, AudibleAlert::CHIME_WARNING_REPEAT);
|
||||
|
||||
// TODO: clean this up once Qt handles the border
|
||||
QUIState::ui_state.status = STATUS_ALERT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isVisible()) {
|
||||
auto c = bg_colors[s.status];
|
||||
float alpha = 0.375 * cos((millis_since_boot() / 1000) * 2 * M_PI * blinking_rate) + 0.625;
|
||||
bg.setRgb(c.r*255, c.g*255, c.b*255, c.a*alpha*255);
|
||||
}
|
||||
}
|
||||
|
||||
void OnroadAlerts::offroadTransition(bool offroad) {
|
||||
stopSounds();
|
||||
setVisible(false);
|
||||
alert_type = "";
|
||||
}
|
||||
|
||||
void OnroadAlerts::updateAlert(const QString &text1, const QString &text2, float blink_rate,
|
||||
const std::string &type, cereal::ControlsState::AlertSize size, AudibleAlert sound) {
|
||||
|
||||
if (alert_type.compare(type) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
stopSounds();
|
||||
if (sound != AudibleAlert::NONE) {
|
||||
playSound(sound);
|
||||
}
|
||||
|
||||
alert_type = type;
|
||||
blinking_rate = blink_rate;
|
||||
title->setText(text1);
|
||||
msg->setText(text2);
|
||||
msg->setVisible(!msg->text().isEmpty());
|
||||
|
||||
if (size == cereal::ControlsState::AlertSize::SMALL) {
|
||||
setFixedHeight(241);
|
||||
title->setStyleSheet("font-size: 70px; font-weight: 500;");
|
||||
} else if (size == cereal::ControlsState::AlertSize::MID) {
|
||||
setFixedHeight(390);
|
||||
msg->setStyleSheet("font-size: 65px; font-weight: 400;");
|
||||
title->setStyleSheet("font-size: 80px; font-weight: 500;");
|
||||
} else if (size == cereal::ControlsState::AlertSize::FULL) {
|
||||
setFixedHeight(vwp_h);
|
||||
int title_size = (title->text().size() > 15) ? 130 : 110;
|
||||
title->setStyleSheet(QString("font-size: %1px; font-weight: 500;").arg(title_size));
|
||||
msg->setStyleSheet("font-size: 90px; font-weight: 400;");
|
||||
}
|
||||
|
||||
setVisible(size != cereal::ControlsState::AlertSize::NONE);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void OnroadAlerts::playSound(AudibleAlert alert) {
|
||||
int loops = sound_map[alert].second ? QSoundEffect::Infinite : 0;
|
||||
sounds[alert].setLoopCount(loops);
|
||||
sounds[alert].setVolume(volume);
|
||||
sounds[alert].play();
|
||||
}
|
||||
|
||||
void OnroadAlerts::stopSounds() {
|
||||
for (auto &kv : sounds) {
|
||||
// Only stop repeating sounds
|
||||
if (kv.second.loopsRemaining() == QSoundEffect::Infinite) {
|
||||
kv.second.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnroadAlerts::paintEvent(QPaintEvent *event) {
|
||||
QPainter p(this);
|
||||
p.setBrush(QBrush(bg));
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawRect(rect());
|
||||
}
|
||||
|
||||
NvgWindow::~NvgWindow() {
|
||||
makeCurrent();
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
void OnroadWindow::initializeGL() {
|
||||
void NvgWindow::initializeGL() {
|
||||
initializeOpenGLFunctions();
|
||||
std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
|
||||
std::cout << "OpenGL vendor: " << glGetString(GL_VENDOR) << std::endl;
|
||||
|
@ -22,22 +184,20 @@ void OnroadWindow::initializeGL() {
|
|||
prev_draw_t = millis_since_boot();
|
||||
}
|
||||
|
||||
void OnroadWindow::update(const UIState &s) {
|
||||
void NvgWindow::update(const UIState &s) {
|
||||
// Connecting to visionIPC requires opengl to be current
|
||||
if (s.vipc_client->connected){
|
||||
makeCurrent();
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void OnroadWindow::paintGL() {
|
||||
void NvgWindow::paintGL() {
|
||||
ui_draw(&QUIState::ui_state, width(), height());
|
||||
|
||||
double cur_draw_t = millis_since_boot();
|
||||
double dt = cur_draw_t - prev_draw_t;
|
||||
// TODO: check if onroad
|
||||
if (dt > 66 && QUIState::ui_state.scene.started && !QUIState::ui_state.scene.driver_view) {
|
||||
if (dt > 66 && !QUIState::ui_state.scene.driver_view) {
|
||||
// warn on sub 15fps
|
||||
LOGW("slow frame time: %.2f", dt);
|
||||
}
|
||||
|
|
|
@ -1,19 +1,68 @@
|
|||
#pragma once
|
||||
#include <map>
|
||||
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLWidget>
|
||||
#include <QTimer>
|
||||
#include <QSoundEffect>
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "ui/ui.h"
|
||||
#include "cereal/gen/cpp/log.capnp.h"
|
||||
#include "selfdrive/hardware/hw.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
|
||||
typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert;
|
||||
|
||||
// ***** onroad widgets *****
|
||||
|
||||
class OnroadAlerts : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OnroadAlerts(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
|
||||
private:
|
||||
QColor bg;
|
||||
QLabel *title, *msg;
|
||||
QVBoxLayout *layout;
|
||||
|
||||
void updateAlert(const QString &text1, const QString &text2, float blink_rate,
|
||||
const std::string &type, cereal::ControlsState::AlertSize size, AudibleAlert sound);
|
||||
|
||||
// sounds
|
||||
std::map<AudibleAlert, std::pair<QString, bool>> sound_map {
|
||||
// AudibleAlert, (file path, inf loop)
|
||||
{AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", false}},
|
||||
{AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", false}},
|
||||
{AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", false}},
|
||||
{AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", false}},
|
||||
{AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", true}},
|
||||
{AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", true}},
|
||||
{AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", false}},
|
||||
{AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", false}}
|
||||
};
|
||||
float volume = Hardware::MIN_VOLUME;
|
||||
float blinking_rate = 0;
|
||||
std::string alert_type;
|
||||
std::map<AudibleAlert, QSoundEffect> sounds;
|
||||
|
||||
void playSound(AudibleAlert alert);
|
||||
void stopSounds();
|
||||
|
||||
public slots:
|
||||
void update(const UIState &s);
|
||||
void offroadTransition(bool offroad);
|
||||
};
|
||||
|
||||
// container window for the NVG UI
|
||||
class OnroadWindow : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||
class NvgWindow : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using QOpenGLWidget::QOpenGLWidget;
|
||||
explicit OnroadWindow(QWidget* parent = 0) : QOpenGLWidget(parent) {};
|
||||
~OnroadWindow();
|
||||
explicit NvgWindow(QWidget* parent = 0) : QOpenGLWidget(parent) {};
|
||||
~NvgWindow();
|
||||
|
||||
protected:
|
||||
void paintGL() override;
|
||||
|
@ -25,3 +74,20 @@ private:
|
|||
public slots:
|
||||
void update(const UIState &s);
|
||||
};
|
||||
|
||||
// container for all onroad widgets
|
||||
class OnroadWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OnroadWindow(QWidget* parent = 0);
|
||||
|
||||
private:
|
||||
OnroadAlerts *alerts;
|
||||
NvgWindow *nvg;
|
||||
QStackedLayout *layout;
|
||||
|
||||
signals:
|
||||
void update(const UIState &s);
|
||||
void offroadTransition(bool offroad);
|
||||
};
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
#include <QUrl>
|
||||
#include "sound.h"
|
||||
|
||||
Sound::Sound() {
|
||||
for (auto &kv : sound_map) {
|
||||
auto path = QUrl::fromLocalFile(kv.second.first);
|
||||
sounds[kv.first].setSource(path);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::play(AudibleAlert alert) {
|
||||
int loops = sound_map[alert].second ? QSoundEffect::Infinite : 0;
|
||||
sounds[alert].setLoopCount(loops);
|
||||
sounds[alert].setVolume(volume);
|
||||
sounds[alert].play();
|
||||
}
|
||||
|
||||
void Sound::stop() {
|
||||
for (auto &kv : sounds) {
|
||||
// Only stop repeating sounds
|
||||
if (kv.second.loopsRemaining() == QSoundEffect::Infinite) {
|
||||
kv.second.stop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <QSoundEffect>
|
||||
#include "cereal/gen/cpp/log.capnp.h"
|
||||
|
||||
typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert;
|
||||
|
||||
class Sound {
|
||||
public:
|
||||
Sound();
|
||||
void play(AudibleAlert alert);
|
||||
void stop();
|
||||
float volume = 0;
|
||||
|
||||
private:
|
||||
std::map<AudibleAlert, std::pair<QString, bool>> sound_map {
|
||||
// AudibleAlert, (file path, inf loop)
|
||||
{AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", false}},
|
||||
{AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", false}},
|
||||
{AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", false}},
|
||||
{AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", false}},
|
||||
{AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", true}},
|
||||
{AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", true}},
|
||||
{AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", false}},
|
||||
{AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", false}}
|
||||
};
|
||||
|
||||
std::map<AudibleAlert, QSoundEffect> sounds;
|
||||
};
|
|
@ -11,6 +11,7 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
|
|||
QObject::connect(homeWindow, &HomeWindow::closeSettings, this, &MainWindow::closeSettings);
|
||||
QObject::connect(&qs, &QUIState::uiUpdate, homeWindow, &HomeWindow::update);
|
||||
QObject::connect(&qs, &QUIState::offroadTransition, homeWindow, &HomeWindow::offroadTransition);
|
||||
QObject::connect(&qs, &QUIState::offroadTransition, homeWindow, &HomeWindow::offroadTransitionSignal);
|
||||
QObject::connect(&device, &Device::displayPowerChanged, homeWindow, &HomeWindow::displayPowerChanged);
|
||||
|
||||
settingsWindow = new SettingsWindow(this);
|
||||
|
|
|
@ -219,46 +219,6 @@ static void update_state(UIState *s) {
|
|||
scene.started = scene.deviceState.getStarted() || scene.driver_view;
|
||||
}
|
||||
|
||||
static void update_alert(UIState *s) {
|
||||
UIScene &scene = s->scene;
|
||||
if (s->sm->updated("controlsState")) {
|
||||
auto alert_sound = scene.controls_state.getAlertSound();
|
||||
if (scene.alert_type.compare(scene.controls_state.getAlertType()) != 0) {
|
||||
s->sound->stop();
|
||||
if (alert_sound != AudibleAlert::NONE) {
|
||||
s->sound->play(alert_sound);
|
||||
}
|
||||
}
|
||||
scene.alert_text1 = scene.controls_state.getAlertText1();
|
||||
scene.alert_text2 = scene.controls_state.getAlertText2();
|
||||
scene.alert_size = scene.controls_state.getAlertSize();
|
||||
scene.alert_type = scene.controls_state.getAlertType();
|
||||
scene.alert_blinking_rate = scene.controls_state.getAlertBlinkingRate();
|
||||
}
|
||||
|
||||
// Handle controls timeout
|
||||
if (scene.deviceState.getStarted() && (s->sm->frame - scene.started_frame) > 10 * UI_FREQ) {
|
||||
const uint64_t cs_frame = s->sm->rcv_frame("controlsState");
|
||||
if (cs_frame < scene.started_frame) {
|
||||
// car is started, but controlsState hasn't been seen at all
|
||||
scene.alert_text1 = "openpilot Unavailable";
|
||||
scene.alert_text2 = "Waiting for controls to start";
|
||||
scene.alert_size = cereal::ControlsState::AlertSize::MID;
|
||||
} else if ((s->sm->frame - cs_frame) > 5 * UI_FREQ) {
|
||||
// car is started, but controls is lagging or died
|
||||
if (scene.alert_text2 != "Controls Unresponsive") {
|
||||
s->sound->play(AudibleAlert::CHIME_WARNING_REPEAT);
|
||||
LOGE("Controls unresponsive");
|
||||
}
|
||||
|
||||
scene.alert_text1 = "TAKE CONTROL IMMEDIATELY";
|
||||
scene.alert_text2 = "Controls Unresponsive";
|
||||
scene.alert_size = cereal::ControlsState::AlertSize::FULL;
|
||||
s->status = STATUS_ALERT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_params(UIState *s) {
|
||||
const uint64_t frame = s->sm->frame;
|
||||
UIScene &scene = s->scene;
|
||||
|
@ -313,11 +273,8 @@ static void update_status(UIState *s) {
|
|||
|
||||
s->scene.is_rhd = Params().getBool("IsRHD");
|
||||
s->scene.end_to_end = Params().getBool("EndToEndToggle");
|
||||
s->scene.alert_size = cereal::ControlsState::AlertSize::NONE;
|
||||
s->vipc_client = s->scene.driver_view ? s->vipc_client_front : s->vipc_client_rear;
|
||||
} else {
|
||||
s->status = STATUS_OFFROAD;
|
||||
s->sound->stop();
|
||||
s->vipc_client->connected = false;
|
||||
}
|
||||
}
|
||||
|
@ -326,7 +283,6 @@ static void update_status(UIState *s) {
|
|||
|
||||
|
||||
QUIState::QUIState(QObject *parent) : QObject(parent) {
|
||||
ui_state.sound = std::make_unique<Sound>();
|
||||
ui_state.sm = std::make_unique<SubMaster, const std::initializer_list<const char *>>({
|
||||
"modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "liveLocationKalman",
|
||||
"pandaState", "carParams", "driverState", "driverMonitoringState", "sensorEvents", "carState", "ubloxGnss",
|
||||
|
@ -338,7 +294,6 @@ QUIState::QUIState(QObject *parent) : QObject(parent) {
|
|||
ui_state.fb_w = vwp_w;
|
||||
ui_state.fb_h = vwp_h;
|
||||
ui_state.scene.started = false;
|
||||
ui_state.status = STATUS_OFFROAD;
|
||||
ui_state.last_frame = nullptr;
|
||||
ui_state.wide_camera = false;
|
||||
|
||||
|
@ -361,7 +316,6 @@ void QUIState::update() {
|
|||
update_sockets(&ui_state);
|
||||
update_state(&ui_state);
|
||||
update_status(&ui_state);
|
||||
update_alert(&ui_state);
|
||||
update_vision(&ui_state);
|
||||
|
||||
if (ui_state.scene.started != started_prev) {
|
||||
|
@ -373,10 +327,6 @@ void QUIState::update() {
|
|||
timer->start(ui_state.scene.started ? 0 : 1000 / UI_FREQ);
|
||||
}
|
||||
|
||||
// scale volume with speed
|
||||
QUIState::ui_state.sound->volume = util::map_val(ui_state.scene.car_state.getVEgo(), 0.f, 20.f,
|
||||
Hardware::MIN_VOLUME, Hardware::MAX_VOLUME);
|
||||
|
||||
watchdog_kick();
|
||||
emit uiUpdate(ui_state);
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include "visionipc.h"
|
||||
#include "visionipc_client.h"
|
||||
|
||||
#include "qt/sound.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
|
@ -57,7 +55,6 @@ typedef enum NetStatus {
|
|||
} NetStatus;
|
||||
|
||||
typedef enum UIStatus {
|
||||
STATUS_OFFROAD,
|
||||
STATUS_DISENGAGED,
|
||||
STATUS_ENGAGED,
|
||||
STATUS_WARNING,
|
||||
|
@ -65,7 +62,6 @@ typedef enum UIStatus {
|
|||
} UIStatus;
|
||||
|
||||
static std::map<UIStatus, NVGcolor> bg_colors = {
|
||||
{STATUS_OFFROAD, nvgRGBA(0x0, 0x0, 0x0, 0xff)},
|
||||
{STATUS_DISENGAGED, nvgRGBA(0x17, 0x33, 0x49, 0xc8)},
|
||||
{STATUS_ENGAGED, nvgRGBA(0x17, 0x86, 0x44, 0xf1)},
|
||||
{STATUS_WARNING, nvgRGBA(0xDA, 0x6F, 0x25, 0xf1)},
|
||||
|
@ -89,12 +85,6 @@ typedef struct UIScene {
|
|||
bool is_rhd;
|
||||
bool driver_view;
|
||||
|
||||
std::string alert_text1;
|
||||
std::string alert_text2;
|
||||
std::string alert_type;
|
||||
float alert_blinking_rate;
|
||||
cereal::ControlsState::AlertSize alert_size;
|
||||
|
||||
cereal::PandaState::PandaType pandaType;
|
||||
NetStatus athenaStatus;
|
||||
|
||||
|
@ -141,7 +131,6 @@ typedef struct UIState {
|
|||
|
||||
std::unique_ptr<SubMaster> sm;
|
||||
|
||||
std::unique_ptr<Sound> sound;
|
||||
UIStatus status;
|
||||
UIScene scene;
|
||||
|
||||
|
|
Loading…
Reference in New Issue