openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
9.1 KiB

#include "tools/cabana/util.h"
#include <algorithm>
macOS: fix build issues & re-enable CI (#28258) * Uncomment build_mac job * Add PYCURL_CURL_CONFIG * Acados universal binary * Remove x86 macos references from sconscript * Add missing include in cabana * Update cereal * Update workflow * Remove unnecessary libpaths for darwin * Add missing path to cached dirs * Fix path in cache preparation step * Add poetry caches to CI cache * Compile acados with lower deployment target for CI * Update cereal * Pass -rpath in linker flags as scons doed not support RPATH on macos * Use scons api instead of os * @rpath in install name of acados dylibs * SConstruct cleanup * fix liblocationd tests by adding lib suffix based on platform * Update cereal * Update opendbc * Update opendbc * Add acados gitignore to release files * Update cereal * Update cereal * Add scons_cache to build cache * Add Caskroom to cache * Fix typo * Link all packages at once, instead of one by one * Run cleanup stage using poetry * Remove casks from cache * Move scons cache to separate cache step * Save scons cache only on master * Remove restore-keys from save-scons-cache step * Uncomment if conditions for scons save * Add gcc-arm-embedded cask cache to cache * Custom handling of gcc-arm-embedded toolchain cache * Rename dep cache key * Exclude .fseventsd from cache * Fix glob pattern * Remove .feventsd before caching * Run mac_setup only if dependency cache-hit != true * Update cereal to master * Add overwrite flag to brew link * Remove manual casadi build from mac_setup * Remove restore-keys from dependency cache * Remove linux requirement for casadi * Restore restore-keys to dependency cache
2 years ago
#include <array>
#include <csignal>
#include <limits>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
macOS: fix build issues & re-enable CI (#28258) * Uncomment build_mac job * Add PYCURL_CURL_CONFIG * Acados universal binary * Remove x86 macos references from sconscript * Add missing include in cabana * Update cereal * Update workflow * Remove unnecessary libpaths for darwin * Add missing path to cached dirs * Fix path in cache preparation step * Add poetry caches to CI cache * Compile acados with lower deployment target for CI * Update cereal * Pass -rpath in linker flags as scons doed not support RPATH on macos * Use scons api instead of os * @rpath in install name of acados dylibs * SConstruct cleanup * fix liblocationd tests by adding lib suffix based on platform * Update cereal * Update opendbc * Update opendbc * Add acados gitignore to release files * Update cereal * Update cereal * Add scons_cache to build cache * Add Caskroom to cache * Fix typo * Link all packages at once, instead of one by one * Run cleanup stage using poetry * Remove casks from cache * Move scons cache to separate cache step * Save scons cache only on master * Remove restore-keys from save-scons-cache step * Uncomment if conditions for scons save * Add gcc-arm-embedded cask cache to cache * Custom handling of gcc-arm-embedded toolchain cache * Rename dep cache key * Exclude .fseventsd from cache * Fix glob pattern * Remove .feventsd before caching * Run mac_setup only if dependency cache-hit != true * Update cereal to master * Add overwrite flag to brew link * Remove manual casadi build from mac_setup * Remove restore-keys from dependency cache * Remove linux requirement for casadi * Restore restore-keys to dependency cache
2 years ago
#include <QDebug>
#include <QColor>
#include <QFontDatabase>
#include <QLocale>
#include <QPainter>
#include <QPixmapCache>
#include "selfdrive/ui/qt/util.h"
// SegmentTree
void SegmentTree::build(const QVector<QPointF> &arr) {
size = arr.size();
tree.resize(4 * size); // size of the tree is 4 times the size of the array
if (size > 0) {
build_tree(arr, 1, 0, size - 1);
}
}
void SegmentTree::build_tree(const QVector<QPointF> &arr, int n, int left, int right) {
if (left == right) {
const double y = arr[left].y();
tree[n] = {y, y};
} else {
const int mid = (left + right) >> 1;
build_tree(arr, 2 * n, left, mid);
build_tree(arr, 2 * n + 1, mid + 1, right);
tree[n] = {std::min(tree[2 * n].first, tree[2 * n + 1].first), std::max(tree[2 * n].second, tree[2 * n + 1].second)};
}
}
std::pair<double, double> SegmentTree::get_minmax(int n, int left, int right, int range_left, int range_right) const {
if (range_left > right || range_right < left)
return {std::numeric_limits<double>::max(), std::numeric_limits<double>::lowest()};
if (range_left <= left && range_right >= right)
return tree[n];
int mid = (left + right) >> 1;
auto l = get_minmax(2 * n, left, mid, range_left, range_right);
auto r = get_minmax(2 * n + 1, mid + 1, right, range_left, range_right);
return {std::min(l.first, r.first), std::max(l.second, r.second)};
}
// MessageBytesDelegate
MessageBytesDelegate::MessageBytesDelegate(QObject *parent, bool multiple_lines) : multiple_lines(multiple_lines), QStyledItemDelegate(parent) {
fixed_font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
byte_size = QFontMetrics(fixed_font).size(Qt::TextSingleLine, "00 ") + QSize(0, 2);
}
int MessageBytesDelegate::widthForBytes(int n) const {
int h_margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
return n * byte_size.width() + h_margin * 2;
}
QSize MessageBytesDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
int v_margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameVMargin) + 1;
auto data = index.data(BytesRole);
if (!data.isValid()) {
return {1, byte_size.height() + 2 * v_margin};
}
int n = data.toByteArray().size();
assert(n >= 0 && n <= 64);
return !multiple_lines ? QSize{widthForBytes(n), byte_size.height() + 2 * v_margin}
: QSize{widthForBytes(8), byte_size.height() * std::max(1, n / 8) + 2 * v_margin};
}
void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
auto data = index.data(BytesRole);
if (!data.isValid()) {
return QStyledItemDelegate::paint(painter, option, index);
}
auto byte_list = data.toByteArray();
auto colors = index.data(ColorsRole).value<QVector<QColor>>();
int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin);
int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
if (option.state & QStyle::State_Selected) {
painter->fillRect(option.rect, option.palette.brush(QPalette::Normal, QPalette::Highlight));
}
const QPoint pt{option.rect.left() + h_margin, option.rect.top() + v_margin};
QFont old_font = painter->font();
QPen old_pen = painter->pen();
painter->setFont(fixed_font);
for (int i = 0; i < byte_list.size(); ++i) {
int row = !multiple_lines ? 0 : i / 8;
int column = !multiple_lines ? i : i % 8;
QRect r = QRect({pt.x() + column * byte_size.width(), pt.y() + row * byte_size.height()}, byte_size);
if (i < colors.size() && colors[i].alpha() > 0) {
if (option.state & QStyle::State_Selected) {
painter->setPen(option.palette.color(QPalette::Text));
painter->fillRect(r, option.palette.color(QPalette::Window));
}
painter->fillRect(r, colors[i]);
} else if (option.state & QStyle::State_Selected) {
painter->setPen(option.palette.color(QPalette::HighlightedText));
}
painter->drawText(r, Qt::AlignCenter, toHex(byte_list[i]));
}
painter->setFont(old_font);
painter->setPen(old_pen);
}
// TabBar
int TabBar::addTab(const QString &text) {
int index = QTabBar::addTab(text);
QToolButton *btn = new ToolButton("x", tr("Close Tab"));
int width = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, nullptr, btn);
int height = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, nullptr, btn);
btn->setFixedSize({width, height});
setTabButton(index, QTabBar::RightSide, btn);
QObject::connect(btn, &QToolButton::clicked, this, &TabBar::closeTabClicked);
return index;
}
void TabBar::closeTabClicked() {
QObject *object = sender();
for (int i = 0; i < count(); ++i) {
if (tabButton(i, QTabBar::RightSide) == object) {
emit tabCloseRequested(i);
break;
}
}
}
// UnixSignalHandler
UnixSignalHandler::UnixSignalHandler(QObject *parent) : QObject(nullptr) {
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sig_fd)) {
qFatal("Couldn't create TERM socketpair");
}
sn = new QSocketNotifier(sig_fd[1], QSocketNotifier::Read, this);
connect(sn, &QSocketNotifier::activated, this, &UnixSignalHandler::handleSigTerm);
std::signal(SIGINT, signalHandler);
std::signal(SIGTERM, UnixSignalHandler::signalHandler);
}
UnixSignalHandler::~UnixSignalHandler() {
::close(sig_fd[0]);
::close(sig_fd[1]);
}
void UnixSignalHandler::signalHandler(int s) {
::write(sig_fd[0], &s, sizeof(s));
}
void UnixSignalHandler::handleSigTerm() {
sn->setEnabled(false);
int tmp;
::read(sig_fd[1], &tmp, sizeof(tmp));
printf("\nexiting...\n");
qApp->closeAllWindows();
qApp->exit();
}
// NameValidator
NameValidator::NameValidator(QObject *parent) : QRegExpValidator(QRegExp("^(\\w+)"), parent) {}
QValidator::State NameValidator::validate(QString &input, int &pos) const {
input.replace(' ', '_');
return QRegExpValidator::validate(input, pos);
}
DoubleValidator::DoubleValidator(QObject *parent) : QDoubleValidator(parent) {
// Match locale of QString::toDouble() instead of system
QLocale locale(QLocale::C);
locale.setNumberOptions(QLocale::RejectGroupSeparator);
setLocale(locale);
}
namespace utils {
QPixmap icon(const QString &id) {
bool dark_theme = settings.theme == DARK_THEME;
QPixmap pm;
QString key = "bootstrap_" % id % (dark_theme ? "1" : "0");
if (!QPixmapCache::find(key, &pm)) {
pm = bootstrapPixmap(id);
if (dark_theme) {
QPainter p(&pm);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(pm.rect(), QColor("#bbbbbb"));
}
QPixmapCache::insert(key, pm);
}
return pm;
}
void setTheme(int theme) {
auto style = QApplication::style();
if (!style) return;
static int prev_theme = 0;
if (theme != prev_theme) {
prev_theme = theme;
QPalette new_palette;
if (theme == DARK_THEME) {
// "Darcula" like dark theme
new_palette.setColor(QPalette::Window, QColor("#353535"));
new_palette.setColor(QPalette::WindowText, QColor("#bbbbbb"));
new_palette.setColor(QPalette::Base, QColor("#3c3f41"));
new_palette.setColor(QPalette::AlternateBase, QColor("#3c3f41"));
new_palette.setColor(QPalette::ToolTipBase, QColor("#3c3f41"));
new_palette.setColor(QPalette::ToolTipText, QColor("#bbb"));
new_palette.setColor(QPalette::Text, QColor("#bbbbbb"));
new_palette.setColor(QPalette::Button, QColor("#3c3f41"));
new_palette.setColor(QPalette::ButtonText, QColor("#bbbbbb"));
new_palette.setColor(QPalette::Highlight, QColor("#2f65ca"));
new_palette.setColor(QPalette::HighlightedText, QColor("#bbbbbb"));
new_palette.setColor(QPalette::BrightText, QColor("#f0f0f0"));
new_palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor("#777777"));
new_palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor("#777777"));
new_palette.setColor(QPalette::Disabled, QPalette::Text, QColor("#777777"));
new_palette.setColor(QPalette::Light, QColor("#777777"));
new_palette.setColor(QPalette::Dark, QColor("#353535"));
} else {
new_palette = style->standardPalette();
}
qApp->setPalette(new_palette);
style->polish(qApp);
for (auto w : QApplication::allWidgets()) {
w->setPalette(new_palette);
}
}
}
} // namespace utils
QString toHex(uint8_t byte) {
static std::array<QString, 256> hex = []() {
std::array<QString, 256> ret;
for (int i = 0; i < 256; ++i) ret[i] = QStringLiteral("%1").arg(i, 2, 16, QLatin1Char('0')).toUpper();
return ret;
}();
return hex[byte];
}
int num_decimals(double num) {
const QString string = QString::number(num);
auto dot_pos = string.indexOf('.');
return dot_pos == -1 ? 0 : string.size() - dot_pos - 1;
}
QString signalToolTip(const cabana::Signal *sig) {
return QObject::tr(R"(
%1<br /><span font-size:small">
Start Bit: %2 Size: %3<br />
MSB: %4 LSB: %5<br />
Little Endian: %6 Signed: %7</span>
)").arg(sig->name).arg(sig->start_bit).arg(sig->size).arg(sig->msb).arg(sig->lsb)
.arg(sig->is_little_endian ? "Y" : "N").arg(sig->is_signed ? "Y" : "N");
}