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.

295 lines
10 KiB

#include "tools/cabana/messageswidget.h"
#include <QHBoxLayout>
#include <QPainter>
#include <QPushButton>
#include <QVBoxLayout>
MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) {
QVBoxLayout *main_layout = new QVBoxLayout(this);
main_layout->setContentsMargins(0 ,0, 0, 0);
Cabana: stable initial release (#26004) * increase form size & fix wrong charts number * set max axisy to 1.0 if no value * show 'close' button in floating window * alwasy show scroll bar * complete the logs * more * increase size to 50 * keep logs for all messages * more * rename signal * better height * avoid flicker * dont call setupdatesenabled * filter dbc files bye typing * remove all charts if dbc file changed * fix wrong idx * bolder dbc filename * update chart if signal has been edited * new signals signalAdded,signalUpdated * split class Parser into CanMessages and DBCManager * cleanup * updateState after set message * cleanup * emit msgUpdated * clear history log if selected range changed * always update time * change title layout * show selected range hide title bar if no charts less space between title and chart * custome historylogmodel for extreme fast update * move historylog to seperate file * 2 decimal * cleanup cleanup * left click on the chart to set start time * todo * show tooltip for header item&cleanup binaryview add hline to signal form * better paint * cleanup signals/slots * better range if min==max * set historylog's minheight to 300 * 3x faster,sortable message list. * zero copy in queued connection * proxymodel * clear log if loop to the begin * simplify history log * remove icon * remove assets * hide linemarker on initialization * rubber width may less than 0 * dont zoom char if selected range is too small * cleanup messageslist * don't zoom chart if selected range less than 500ms * typo * check boundary * check msg_id * capital first letter * move history log out of scrollarea * Show only one form at a time * auto scroll to header d * reduce msg size entire row clickable rename filter_msgs old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
3 years ago
// message filter
QHBoxLayout *title_layout = new QHBoxLayout();
title_layout->addWidget(filter = new QLineEdit(this));
QRegularExpression re("\\S+");
filter->setValidator(new QRegularExpressionValidator(re, this));
filter->setClearButtonEnabled(true);
filter->setPlaceholderText(tr("filter messages"));
title_layout->addWidget(multiple_lines_bytes = new QCheckBox(tr("Multiple Lines Bytes"), this));
multiple_lines_bytes->setToolTip(tr("Display bytes in multiple lines"));
multiple_lines_bytes->setChecked(settings.multiple_lines_bytes);
main_layout->addLayout(title_layout);
Cabana: stable initial release (#26004) * increase form size & fix wrong charts number * set max axisy to 1.0 if no value * show 'close' button in floating window * alwasy show scroll bar * complete the logs * more * increase size to 50 * keep logs for all messages * more * rename signal * better height * avoid flicker * dont call setupdatesenabled * filter dbc files bye typing * remove all charts if dbc file changed * fix wrong idx * bolder dbc filename * update chart if signal has been edited * new signals signalAdded,signalUpdated * split class Parser into CanMessages and DBCManager * cleanup * updateState after set message * cleanup * emit msgUpdated * clear history log if selected range changed * always update time * change title layout * show selected range hide title bar if no charts less space between title and chart * custome historylogmodel for extreme fast update * move historylog to seperate file * 2 decimal * cleanup cleanup * left click on the chart to set start time * todo * show tooltip for header item&cleanup binaryview add hline to signal form * better paint * cleanup signals/slots * better range if min==max * set historylog's minheight to 300 * 3x faster,sortable message list. * zero copy in queued connection * proxymodel * clear log if loop to the begin * simplify history log * remove icon * remove assets * hide linemarker on initialization * rubber width may less than 0 * dont zoom char if selected range is too small * cleanup messageslist * don't zoom chart if selected range less than 500ms * typo * check boundary * check msg_id * capital first letter * move history log out of scrollarea * Show only one form at a time * auto scroll to header d * reduce msg size entire row clickable rename filter_msgs old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
3 years ago
// message table
view = new MessageView(this);
Cabana: stable initial release (#26004) * increase form size & fix wrong charts number * set max axisy to 1.0 if no value * show 'close' button in floating window * alwasy show scroll bar * complete the logs * more * increase size to 50 * keep logs for all messages * more * rename signal * better height * avoid flicker * dont call setupdatesenabled * filter dbc files bye typing * remove all charts if dbc file changed * fix wrong idx * bolder dbc filename * update chart if signal has been edited * new signals signalAdded,signalUpdated * split class Parser into CanMessages and DBCManager * cleanup * updateState after set message * cleanup * emit msgUpdated * clear history log if selected range changed * always update time * change title layout * show selected range hide title bar if no charts less space between title and chart * custome historylogmodel for extreme fast update * move historylog to seperate file * 2 decimal * cleanup cleanup * left click on the chart to set start time * todo * show tooltip for header item&cleanup binaryview add hline to signal form * better paint * cleanup signals/slots * better range if min==max * set historylog's minheight to 300 * 3x faster,sortable message list. * zero copy in queued connection * proxymodel * clear log if loop to the begin * simplify history log * remove icon * remove assets * hide linemarker on initialization * rubber width may less than 0 * dont zoom char if selected range is too small * cleanup messageslist * don't zoom chart if selected range less than 500ms * typo * check boundary * check msg_id * capital first letter * move history log out of scrollarea * Show only one form at a time * auto scroll to header d * reduce msg size entire row clickable rename filter_msgs old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
3 years ago
model = new MessageListModel(this);
auto delegate = new MessageBytesDelegate(view, settings.multiple_lines_bytes);
view->setItemDelegate(delegate);
view->setModel(model);
view->setSortingEnabled(true);
view->sortByColumn(0, Qt::AscendingOrder);
view->setAllColumnsShowFocus(true);
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
view->setItemsExpandable(false);
view->setIndentation(0);
view->setRootIsDecorated(false);
view->header()->setSectionsMovable(false);
main_layout->addWidget(view);
// suppress
QHBoxLayout *suppress_layout = new QHBoxLayout();
suppress_add = new QPushButton("Suppress Highlighted");
suppress_clear = new QPushButton();
suppress_layout->addWidget(suppress_add);
suppress_layout->addWidget(suppress_clear);
main_layout->addLayout(suppress_layout);
Cabana: stable initial release (#26004) * increase form size & fix wrong charts number * set max axisy to 1.0 if no value * show 'close' button in floating window * alwasy show scroll bar * complete the logs * more * increase size to 50 * keep logs for all messages * more * rename signal * better height * avoid flicker * dont call setupdatesenabled * filter dbc files bye typing * remove all charts if dbc file changed * fix wrong idx * bolder dbc filename * update chart if signal has been edited * new signals signalAdded,signalUpdated * split class Parser into CanMessages and DBCManager * cleanup * updateState after set message * cleanup * emit msgUpdated * clear history log if selected range changed * always update time * change title layout * show selected range hide title bar if no charts less space between title and chart * custome historylogmodel for extreme fast update * move historylog to seperate file * 2 decimal * cleanup cleanup * left click on the chart to set start time * todo * show tooltip for header item&cleanup binaryview add hline to signal form * better paint * cleanup signals/slots * better range if min==max * set historylog's minheight to 300 * 3x faster,sortable message list. * zero copy in queued connection * proxymodel * clear log if loop to the begin * simplify history log * remove icon * remove assets * hide linemarker on initialization * rubber width may less than 0 * dont zoom char if selected range is too small * cleanup messageslist * don't zoom chart if selected range less than 500ms * typo * check boundary * check msg_id * capital first letter * move history log out of scrollarea * Show only one form at a time * auto scroll to header d * reduce msg size entire row clickable rename filter_msgs old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
3 years ago
// signals/slots
QObject::connect(filter, &QLineEdit::textEdited, model, &MessageListModel::setFilterString);
QObject::connect(multiple_lines_bytes, &QCheckBox::stateChanged, [=](int state) {
settings.multiple_lines_bytes = (state == Qt::Checked);
delegate->setMultipleLines(settings.multiple_lines_bytes);
view->setUniformRowHeights(!settings.multiple_lines_bytes);
model->sortMessages();
});
QObject::connect(can, &AbstractStream::msgsReceived, model, &MessageListModel::msgsReceived);
QObject::connect(can, &AbstractStream::streamStarted, this, &MessagesWidget::reset);
QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages);
QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages);
QObject::connect(dbc(), &DBCManager::msgRemoved, model, &MessageListModel::sortMessages);
QObject::connect(model, &MessageListModel::modelReset, [this]() {
if (current_msg_id) {
selectMessage(*current_msg_id);
}
});
QObject::connect(view->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex &current, const QModelIndex &previous) {
if (current.isValid() && current.row() < model->msgs.size()) {
auto &id = model->msgs[current.row()];
if (!current_msg_id || id != *current_msg_id) {
current_msg_id = id;
emit msgSelectionChanged(*current_msg_id);
}
Cabana: stable initial release (#26004) * increase form size & fix wrong charts number * set max axisy to 1.0 if no value * show 'close' button in floating window * alwasy show scroll bar * complete the logs * more * increase size to 50 * keep logs for all messages * more * rename signal * better height * avoid flicker * dont call setupdatesenabled * filter dbc files bye typing * remove all charts if dbc file changed * fix wrong idx * bolder dbc filename * update chart if signal has been edited * new signals signalAdded,signalUpdated * split class Parser into CanMessages and DBCManager * cleanup * updateState after set message * cleanup * emit msgUpdated * clear history log if selected range changed * always update time * change title layout * show selected range hide title bar if no charts less space between title and chart * custome historylogmodel for extreme fast update * move historylog to seperate file * 2 decimal * cleanup cleanup * left click on the chart to set start time * todo * show tooltip for header item&cleanup binaryview add hline to signal form * better paint * cleanup signals/slots * better range if min==max * set historylog's minheight to 300 * 3x faster,sortable message list. * zero copy in queued connection * proxymodel * clear log if loop to the begin * simplify history log * remove icon * remove assets * hide linemarker on initialization * rubber width may less than 0 * dont zoom char if selected range is too small * cleanup messageslist * don't zoom chart if selected range less than 500ms * typo * check boundary * check msg_id * capital first letter * move history log out of scrollarea * Show only one form at a time * auto scroll to header d * reduce msg size entire row clickable rename filter_msgs old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
3 years ago
}
});
QObject::connect(suppress_add, &QPushButton::clicked, [=]() {
model->suppress();
updateSuppressedButtons();
});
QObject::connect(suppress_clear, &QPushButton::clicked, [=]() {
model->clearSuppress();
updateSuppressedButtons();
});
updateSuppressedButtons();
setWhatsThis(tr(R"(
<b>Message View</b><br/>
<!-- TODO: add descprition here -->
<span style="color:gray">Byte color</span><br />
<span style="color:gray;"> </span> constant changing<br />
<span style="color:blue;"> </span> increasing<br />
<span style="color:red;"> </span> decreasing
)"));
}
void MessagesWidget::selectMessage(const MessageId &msg_id) {
if (int row = model->msgs.indexOf(msg_id); row != -1) {
view->selectionModel()->setCurrentIndex(model->index(row, 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
}
}
void MessagesWidget::updateSuppressedButtons() {
if (model->suppressed_bytes.empty()) {
suppress_clear->setEnabled(false);
suppress_clear->setText("Clear Suppressed");
} else {
suppress_clear->setEnabled(true);
suppress_clear->setText(QString("Clear Suppressed (%1)").arg(model->suppressed_bytes.size()));
}
}
void MessagesWidget::reset() {
current_msg_id = std::nullopt;
view->selectionModel()->clear();
model->reset();
filter->clear();
updateSuppressedButtons();
}
Cabana: stable initial release (#26004) * increase form size & fix wrong charts number * set max axisy to 1.0 if no value * show 'close' button in floating window * alwasy show scroll bar * complete the logs * more * increase size to 50 * keep logs for all messages * more * rename signal * better height * avoid flicker * dont call setupdatesenabled * filter dbc files bye typing * remove all charts if dbc file changed * fix wrong idx * bolder dbc filename * update chart if signal has been edited * new signals signalAdded,signalUpdated * split class Parser into CanMessages and DBCManager * cleanup * updateState after set message * cleanup * emit msgUpdated * clear history log if selected range changed * always update time * change title layout * show selected range hide title bar if no charts less space between title and chart * custome historylogmodel for extreme fast update * move historylog to seperate file * 2 decimal * cleanup cleanup * left click on the chart to set start time * todo * show tooltip for header item&cleanup binaryview add hline to signal form * better paint * cleanup signals/slots * better range if min==max * set historylog's minheight to 300 * 3x faster,sortable message list. * zero copy in queued connection * proxymodel * clear log if loop to the begin * simplify history log * remove icon * remove assets * hide linemarker on initialization * rubber width may less than 0 * dont zoom char if selected range is too small * cleanup messageslist * don't zoom chart if selected range less than 500ms * typo * check boundary * check msg_id * capital first letter * move history log out of scrollarea * Show only one form at a time * auto scroll to header d * reduce msg size entire row clickable rename filter_msgs old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
3 years ago
// MessageListModel
QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
static const QString titles[] = {"Name", "Bus", "ID", "Freq", "Count", "Bytes"};
return titles[section];
}
Cabana: stable initial release (#26004) * increase form size & fix wrong charts number * set max axisy to 1.0 if no value * show 'close' button in floating window * alwasy show scroll bar * complete the logs * more * increase size to 50 * keep logs for all messages * more * rename signal * better height * avoid flicker * dont call setupdatesenabled * filter dbc files bye typing * remove all charts if dbc file changed * fix wrong idx * bolder dbc filename * update chart if signal has been edited * new signals signalAdded,signalUpdated * split class Parser into CanMessages and DBCManager * cleanup * updateState after set message * cleanup * emit msgUpdated * clear history log if selected range changed * always update time * change title layout * show selected range hide title bar if no charts less space between title and chart * custome historylogmodel for extreme fast update * move historylog to seperate file * 2 decimal * cleanup cleanup * left click on the chart to set start time * todo * show tooltip for header item&cleanup binaryview add hline to signal form * better paint * cleanup signals/slots * better range if min==max * set historylog's minheight to 300 * 3x faster,sortable message list. * zero copy in queued connection * proxymodel * clear log if loop to the begin * simplify history log * remove icon * remove assets * hide linemarker on initialization * rubber width may less than 0 * dont zoom char if selected range is too small * cleanup messageslist * don't zoom chart if selected range less than 500ms * typo * check boundary * check msg_id * capital first letter * move history log out of scrollarea * Show only one form at a time * auto scroll to header d * reduce msg size entire row clickable rename filter_msgs old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
3 years ago
return {};
}
QVariant MessageListModel::data(const QModelIndex &index, int role) const {
const auto &id = msgs[index.row()];
auto &can_data = can->lastMessage(id);
Cabana: stable initial release (#26004) * increase form size & fix wrong charts number * set max axisy to 1.0 if no value * show 'close' button in floating window * alwasy show scroll bar * complete the logs * more * increase size to 50 * keep logs for all messages * more * rename signal * better height * avoid flicker * dont call setupdatesenabled * filter dbc files bye typing * remove all charts if dbc file changed * fix wrong idx * bolder dbc filename * update chart if signal has been edited * new signals signalAdded,signalUpdated * split class Parser into CanMessages and DBCManager * cleanup * updateState after set message * cleanup * emit msgUpdated * clear history log if selected range changed * always update time * change title layout * show selected range hide title bar if no charts less space between title and chart * custome historylogmodel for extreme fast update * move historylog to seperate file * 2 decimal * cleanup cleanup * left click on the chart to set start time * todo * show tooltip for header item&cleanup binaryview add hline to signal form * better paint * cleanup signals/slots * better range if min==max * set historylog's minheight to 300 * 3x faster,sortable message list. * zero copy in queued connection * proxymodel * clear log if loop to the begin * simplify history log * remove icon * remove assets * hide linemarker on initialization * rubber width may less than 0 * dont zoom char if selected range is too small * cleanup messageslist * don't zoom chart if selected range less than 500ms * typo * check boundary * check msg_id * capital first letter * move history log out of scrollarea * Show only one form at a time * auto scroll to header d * reduce msg size entire row clickable rename filter_msgs old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
3 years ago
if (role == Qt::DisplayRole) {
switch (index.column()) {
case 0: return msgName(id);
case 1: return id.source;
case 2: return QString::number(id.address, 16);;
case 3: return can_data.freq;
case 4: return can_data.count;
case 5: return toHex(can_data.dat);
}
} else if (role == ColorsRole) {
QVector<QColor> colors = can_data.colors;
if (!suppressed_bytes.empty()) {
for (int i = 0; i < colors.size(); i++) {
if (suppressed_bytes.contains({id, i})) {
colors[i] = QColor(255, 255, 255, 0);
}
}
}
return QVariant::fromValue(colors);
} else if (role == BytesRole && index.column() == 5) {
return can_data.dat;
Cabana: stable initial release (#26004) * increase form size & fix wrong charts number * set max axisy to 1.0 if no value * show 'close' button in floating window * alwasy show scroll bar * complete the logs * more * increase size to 50 * keep logs for all messages * more * rename signal * better height * avoid flicker * dont call setupdatesenabled * filter dbc files bye typing * remove all charts if dbc file changed * fix wrong idx * bolder dbc filename * update chart if signal has been edited * new signals signalAdded,signalUpdated * split class Parser into CanMessages and DBCManager * cleanup * updateState after set message * cleanup * emit msgUpdated * clear history log if selected range changed * always update time * change title layout * show selected range hide title bar if no charts less space between title and chart * custome historylogmodel for extreme fast update * move historylog to seperate file * 2 decimal * cleanup cleanup * left click on the chart to set start time * todo * show tooltip for header item&cleanup binaryview add hline to signal form * better paint * cleanup signals/slots * better range if min==max * set historylog's minheight to 300 * 3x faster,sortable message list. * zero copy in queued connection * proxymodel * clear log if loop to the begin * simplify history log * remove icon * remove assets * hide linemarker on initialization * rubber width may less than 0 * dont zoom char if selected range is too small * cleanup messageslist * don't zoom chart if selected range less than 500ms * typo * check boundary * check msg_id * capital first letter * move history log out of scrollarea * Show only one form at a time * auto scroll to header d * reduce msg size entire row clickable rename filter_msgs old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
3 years ago
}
return {};
}
void MessageListModel::setFilterString(const QString &string) {
auto contains = [](const MessageId &id, const QString &txt) {
auto cs = Qt::CaseInsensitive;
if (id.toString().contains(txt, cs) || msgName(id).contains(txt, cs)) return true;
// Search by signal name
if (const auto msg = dbc()->msg(id)) {
for (auto s : msg->getSignals()) {
if (s->name.contains(txt, cs)) return true;
}
}
return false;
};
filter_str = string;
msgs.clear();
for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) {
if (filter_str.isEmpty() || contains(it.key(), filter_str)) {
msgs.push_back(it.key());
}
}
sortMessages();
}
void MessageListModel::sortMessages() {
beginResetModel();
if (sort_column == 0) {
std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) {
auto ll = std::pair{msgName(l), l};
auto rr = std::pair{msgName(r), r};
return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr;
});
} else if (sort_column == 1) {
std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) {
auto ll = std::pair{l.source, l};
auto rr = std::pair{r.source, r};
return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr;
});
} else if (sort_column == 2) {
std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) {
auto ll = std::pair{l.address, l};
auto rr = std::pair{r.address, r};
return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr;
});
} else if (sort_column == 3) {
std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) {
auto ll = std::pair{can->lastMessage(l).freq, l};
auto rr = std::pair{can->lastMessage(r).freq, r};
return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr;
});
} else if (sort_column == 4) {
std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) {
auto ll = std::pair{can->lastMessage(l).count, l};
auto rr = std::pair{can->lastMessage(r).count, r};
return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr;
});
}
endResetModel();
}
void MessageListModel::msgsReceived(const QHash<MessageId, CanData> *new_msgs) {
int prev_row_count = msgs.size();
if (filter_str.isEmpty() && msgs.size() != can->last_msgs.size()) {
msgs = can->last_msgs.keys();
}
if (msgs.size() != prev_row_count) {
sortMessages();
return;
}
for (int i = 0; i < msgs.size(); ++i) {
if (new_msgs->contains(msgs[i])) {
for (int col = 3; col < columnCount(); ++col)
emit dataChanged(index(i, col), index(i, col), {Qt::DisplayRole});
}
}
}
void MessageListModel::sort(int column, Qt::SortOrder order) {
if (column != columnCount() - 1) {
sort_column = column;
sort_order = order;
sortMessages();
}
}
void MessageListModel::suppress() {
const double cur_ts = can->currentSec();
for (auto &id : msgs) {
auto &can_data = can->lastMessage(id);
for (int i = 0; i < can_data.dat.size(); i++) {
const double dt = cur_ts - can_data.last_change_t[i];
if (dt < 2.0) {
suppressed_bytes.insert({id, i});
}
}
}
}
void MessageListModel::clearSuppress() {
suppressed_bytes.clear();
}
void MessageListModel::reset() {
beginResetModel();
filter_str = "";
msgs.clear();
clearSuppress();
endResetModel();
}
// MessageView
void MessageView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
QTreeView::drawRow(painter, option, index);
const int gridHint = style()->styleHint(QStyle::SH_Table_GridLineColor, &option, this);
const QColor gridColor = QColor::fromRgba(static_cast<QRgb>(gridHint));
QPen old_pen = painter->pen();
painter->setPen(gridColor);
painter->drawLine(option.rect.left(), option.rect.bottom(), option.rect.right(), option.rect.bottom());
auto y = option.rect.y();
painter->translate(visualRect(model()->index(0, 0)).x() - indentation() - .5, -.5);
for (int i = 0; i < header()->count(); ++i) {
painter->translate(header()->sectionSize(i), 0);
painter->drawLine(0, y, 0, y + option.rect.height());
}
painter->setPen(old_pen);
painter->resetTransform();
}
void MessageView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) {
// Bypass the slow call to QTreeView::dataChanged.
// QTreeView::dataChanged will invalidate the height cache and that's what we don't need in MessageView.
QAbstractItemView::dataChanged(topLeft, bottomRight, roles);
}