cabana: refactor Msg and Signal into dbc.cc (#27552)

old-commit-hash: e4d591ecbf
This commit is contained in:
Willem Melching 2023-03-10 20:19:37 +01:00 committed by GitHub
parent faf6e27f46
commit f0d648d8c6
23 changed files with 295 additions and 301 deletions

View File

@ -28,7 +28,7 @@ cabana_env.Depends(assets, Glob('/assets/*', exclude=[assets, assets_src, "asset
prev_moc_path = cabana_env['QT_MOCHPREFIX']
cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_'
cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc',
cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbc.cc', 'dbcmanager.cc',
'commands.cc', 'messageswidget.cc', 'route.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks)
cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs, FRAMEWORKS=base_frameworks)

View File

@ -75,8 +75,8 @@ void BinaryView::addShortcuts() {
QShortcut *shortcut_endian = new QShortcut(QKeySequence(Qt::Key_E), this);
QObject::connect(shortcut_endian, &QShortcut::activated, [=]{
if (hovered_sig != nullptr) {
const Signal *hovered_sig_prev = hovered_sig;
Signal s = *hovered_sig;
const cabana::Signal *hovered_sig_prev = hovered_sig;
cabana::Signal s = *hovered_sig;
s.is_little_endian = !s.is_little_endian;
emit editSignal(hovered_sig, s);
@ -89,8 +89,8 @@ void BinaryView::addShortcuts() {
QShortcut *shortcut_sign = new QShortcut(QKeySequence(Qt::Key_S), this);
QObject::connect(shortcut_sign, &QShortcut::activated, [=]{
if (hovered_sig != nullptr) {
const Signal *hovered_sig_prev = hovered_sig;
Signal s = *hovered_sig;
const cabana::Signal *hovered_sig_prev = hovered_sig;
cabana::Signal s = *hovered_sig;
s.is_signed = !s.is_signed;
emit editSignal(hovered_sig, s);
@ -117,7 +117,7 @@ QSize BinaryView::minimumSizeHint() const {
CELL_HEIGHT * std::min(model->rowCount(), 10) + 2};
}
void BinaryView::highlight(const Signal *sig) {
void BinaryView::highlight(const cabana::Signal *sig) {
if (sig != hovered_sig) {
for (int i = 0; i < model->items.size(); ++i) {
auto &item_sigs = model->items[i].sigs;
@ -176,7 +176,7 @@ void BinaryView::mousePressEvent(QMouseEvent *event) {
void BinaryView::highlightPosition(const QPoint &pos) {
if (auto index = indexAt(viewport()->mapFromGlobal(pos)); index.isValid()) {
auto item = (BinaryViewModel::Item *)index.internalPointer();
const Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back();
const cabana::Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back();
highlight(sig);
}
}
@ -226,8 +226,8 @@ void BinaryView::refresh() {
highlightPosition(QCursor::pos());
}
QSet<const Signal *> BinaryView::getOverlappingSignals() const {
QSet<const Signal *> overlapping;
QSet<const cabana::Signal *> BinaryView::getOverlappingSignals() const {
QSet<const cabana::Signal *> overlapping;
for (auto &item : model->items) {
if (item.sigs.size() > 1)
for (auto s : item.sigs) overlapping += s;

View File

@ -8,7 +8,6 @@
#include "tools/cabana/dbcmanager.h"
#include "tools/cabana/streams/abstractstream.h"
using namespace dbcmanager;
class BinaryItemDelegate : public QStyledItemDelegate {
public:
@ -44,7 +43,7 @@ public:
bool is_msb = false;
bool is_lsb = false;
QString val = "-";
QList<const Signal *> sigs;
QList<const cabana::Signal *> sigs;
};
std::vector<Item> items;
@ -59,19 +58,19 @@ class BinaryView : public QTableView {
public:
BinaryView(QWidget *parent = nullptr);
void setMessage(const MessageId &message_id);
void highlight(const Signal *sig);
QSet<const Signal*> getOverlappingSignals() const;
void highlight(const cabana::Signal *sig);
QSet<const cabana::Signal*> getOverlappingSignals() const;
inline void updateState() { model->updateState(); }
QSize minimumSizeHint() const override;
signals:
void signalClicked(const Signal *sig);
void signalHovered(const Signal *sig);
void signalClicked(const cabana::Signal *sig);
void signalHovered(const cabana::Signal *sig);
void addSignal(int start_bit, int size, bool little_endian);
void resizeSignal(const Signal *sig, int from, int size);
void removeSignal(const Signal *sig);
void editSignal(const Signal *origin_s, Signal &s);
void showChart(const MessageId &id, const Signal *sig, bool show, bool merge);
void resizeSignal(const cabana::Signal *sig, int from, int size);
void removeSignal(const cabana::Signal *sig);
void editSignal(const cabana::Signal *origin_s, cabana::Signal &s);
void showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge);
private:
void addShortcuts();
@ -87,7 +86,7 @@ private:
QModelIndex anchor_index;
BinaryViewModel *model;
BinaryItemDelegate *delegate;
const Signal *resize_sig = nullptr;
const Signal *hovered_sig = nullptr;
const cabana::Signal *resize_sig = nullptr;
const cabana::Signal *hovered_sig = nullptr;
friend class BinaryItemDelegate;
};

View File

@ -189,7 +189,7 @@ void ChartsWidget::settingChanged() {
}
}
ChartView *ChartsWidget::findChart(const MessageId &id, const Signal *sig) {
ChartView *ChartsWidget::findChart(const MessageId &id, const cabana::Signal *sig) {
for (auto c : charts)
if (c->hasSeries(id, sig)) return c;
return nullptr;
@ -212,7 +212,7 @@ ChartView *ChartsWidget::createChart() {
return chart;
}
void ChartsWidget::showChart(const MessageId &id, const Signal *sig, bool show, bool merge) {
void ChartsWidget::showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge) {
ChartView *chart = findChart(id, sig);
if (show && !chart) {
chart = merge && charts.size() > 0 ? charts.back() : createChart();
@ -377,7 +377,7 @@ void ChartView::createToolButtons() {
});
}
void ChartView::addSeries(const MessageId &msg_id, const Signal *sig) {
void ChartView::addSeries(const MessageId &msg_id, const cabana::Signal *sig) {
if (hasSeries(msg_id, sig)) return;
QXYSeries *series = createSeries(series_type, getColor(sig));
@ -388,7 +388,7 @@ void ChartView::addSeries(const MessageId &msg_id, const Signal *sig) {
emit seriesAdded(msg_id, sig);
}
bool ChartView::hasSeries(const MessageId &msg_id, const Signal *sig) const {
bool ChartView::hasSeries(const MessageId &msg_id, const cabana::Signal *sig) const {
return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; });
}
@ -413,7 +413,7 @@ void ChartView::removeIf(std::function<bool(const SigItem &s)> predicate) {
}
}
void ChartView::signalUpdated(const Signal *sig) {
void ChartView::signalUpdated(const cabana::Signal *sig) {
if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.sig == sig; })) {
updateTitle();
// TODO: don't update series if only name changed.
@ -502,7 +502,7 @@ void ChartView::updateSeriesPoints() {
}
}
void ChartView::updateSeries(const Signal *sig, const std::vector<Event *> *events, bool clear) {
void ChartView::updateSeries(const cabana::Signal *sig, const std::vector<Event *> *events, bool clear) {
events = events ? events : can->events();
for (auto &s : sigs) {
if (!sig || s.sig == sig) {
@ -980,7 +980,7 @@ void SeriesSelector::updateAvailableList(int index) {
}
}
void SeriesSelector::addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name) {
void SeriesSelector::addItemToList(QListWidget *parent, const MessageId id, const cabana::Signal *sig, bool show_msg_name) {
QString text = QString("<span style=\"color:%0;\">■ </span> %1").arg(getColor(sig).name(), sig->name);
if (show_msg_name) text += QString(" <font color=\"gray\">%0 %1</font>").arg(msgName(id), id.toString());

View File

@ -15,7 +15,6 @@
#include "tools/cabana/dbcmanager.h"
#include "tools/cabana/streams/abstractstream.h"
using namespace dbcmanager;
using namespace QtCharts;
const int CHART_MIN_WIDTH = 300;
@ -31,16 +30,16 @@ class ChartView : public QChartView {
public:
ChartView(QWidget *parent = nullptr);
void addSeries(const MessageId &msg_id, const Signal *sig);
bool hasSeries(const MessageId &msg_id, const Signal *sig) const;
void updateSeries(const Signal *sig = nullptr, const std::vector<Event*> *events = nullptr, bool clear = true);
void addSeries(const MessageId &msg_id, const cabana::Signal *sig);
bool hasSeries(const MessageId &msg_id, const cabana::Signal *sig) const;
void updateSeries(const cabana::Signal *sig = nullptr, const std::vector<Event*> *events = nullptr, bool clear = true);
void updatePlot(double cur, double min, double max);
void setSeriesType(SeriesType type);
void updatePlotArea(int left);
struct SigItem {
MessageId msg_id;
const Signal *sig = nullptr;
const cabana::Signal *sig = nullptr;
QXYSeries *series = nullptr;
QVector<QPointF> vals;
QVector<QPointF> step_vals;
@ -50,8 +49,8 @@ public:
};
signals:
void seriesRemoved(const MessageId &id, const Signal *sig);
void seriesAdded(const MessageId &id, const Signal *sig);
void seriesRemoved(const MessageId &id, const cabana::Signal *sig);
void seriesAdded(const MessageId &id, const cabana::Signal *sig);
void zoomIn(double min, double max);
void zoomReset();
void remove();
@ -59,11 +58,11 @@ signals:
private slots:
void msgUpdated(uint32_t address);
void signalUpdated(const Signal *sig);
void signalUpdated(const cabana::Signal *sig);
void manageSeries();
void handleMarkerClicked();
void msgRemoved(uint32_t address) { removeIf([=](auto &s) { return s.msg_id.address == address; }); }
void signalRemoved(const Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); }
void signalRemoved(const cabana::Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); }
private:
void createToolButtons();
@ -107,8 +106,8 @@ class ChartsWidget : public QFrame {
public:
ChartsWidget(QWidget *parent = nullptr);
void showChart(const MessageId &id, const Signal *sig, bool show, bool merge);
inline bool hasSignal(const MessageId &id, const Signal *sig) { return findChart(id, sig) != nullptr; }
void showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge);
inline bool hasSignal(const MessageId &id, const cabana::Signal *sig) { return findChart(id, sig) != nullptr; }
public slots:
void setColumnCount(int n);
@ -134,7 +133,7 @@ private:
void updateLayout();
void settingChanged();
bool eventFilter(QObject *obj, QEvent *event) override;
ChartView *findChart(const MessageId &id, const Signal *sig);
ChartView *findChart(const MessageId &id, const cabana::Signal *sig);
QLabel *title_label;
QLabel *range_lb;
@ -160,18 +159,18 @@ private:
class SeriesSelector : public QDialog {
public:
struct ListItem : public QListWidgetItem {
ListItem(const MessageId &msg_id, const Signal *sig, QListWidget *parent) : msg_id(msg_id), sig(sig), QListWidgetItem(parent) {}
ListItem(const MessageId &msg_id, const cabana::Signal *sig, QListWidget *parent) : msg_id(msg_id), sig(sig), QListWidgetItem(parent) {}
MessageId msg_id;
const Signal *sig;
const cabana::Signal *sig;
};
SeriesSelector(QString title, QWidget *parent);
QList<ListItem *> seletedItems();
inline void addSelected(const MessageId &id, const Signal *sig) { addItemToList(selected_list, id, sig, true); }
inline void addSelected(const MessageId &id, const cabana::Signal *sig) { addItemToList(selected_list, id, sig, true); }
private:
void updateAvailableList(int index);
void addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name = false);
void addItemToList(QListWidget *parent, const MessageId id, const cabana::Signal *sig, bool show_msg_name = false);
void add(QListWidgetItem *item);
void remove(QListWidgetItem *item);

View File

@ -50,7 +50,7 @@ void RemoveMsgCommand::redo() {
// AddSigCommand
AddSigCommand::AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent)
AddSigCommand::AddSigCommand(const MessageId &id, const cabana::Signal &sig, QUndoCommand *parent)
: id(id), signal(sig), QUndoCommand(parent) {
setText(QObject::tr("add signal %1 to %2:%3").arg(sig.name).arg(msgName(id)).arg(id.address));
}
@ -60,7 +60,7 @@ void AddSigCommand::redo() { dbc()->addSignal(id, signal); }
// RemoveSigCommand
RemoveSigCommand::RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent)
RemoveSigCommand::RemoveSigCommand(const MessageId &id, const cabana::Signal *sig, QUndoCommand *parent)
: id(id), signal(*sig), QUndoCommand(parent) {
setText(QObject::tr("remove signal %1 from %2:%3").arg(signal.name).arg(msgName(id)).arg(id.address));
}
@ -70,7 +70,7 @@ void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name); }
// EditSignalCommand
EditSignalCommand::EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent)
EditSignalCommand::EditSignalCommand(const MessageId &id, const cabana::Signal *sig, const cabana::Signal &new_sig, QUndoCommand *parent)
: id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) {
setText(QObject::tr("edit signal %1 in %2:%3").arg(old_signal.name).arg(msgName(id)).arg(id.address));
}

View File

@ -5,7 +5,6 @@
#include "tools/cabana/dbcmanager.h"
#include "tools/cabana/streams/abstractstream.h"
using namespace dbcmanager;
class EditMsgCommand : public QUndoCommand {
public:
@ -27,41 +26,41 @@ public:
private:
const MessageId id;
Msg message;
cabana::Msg message;
};
class AddSigCommand : public QUndoCommand {
public:
AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent = nullptr);
AddSigCommand(const MessageId &id, const cabana::Signal &sig, QUndoCommand *parent = nullptr);
void undo() override;
void redo() override;
private:
const MessageId id;
Signal signal = {};
cabana::Signal signal = {};
};
class RemoveSigCommand : public QUndoCommand {
public:
RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent = nullptr);
RemoveSigCommand(const MessageId &id, const cabana::Signal *sig, QUndoCommand *parent = nullptr);
void undo() override;
void redo() override;
private:
const MessageId id;
Signal signal = {};
cabana::Signal signal = {};
};
class EditSignalCommand : public QUndoCommand {
public:
EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent = nullptr);
EditSignalCommand(const MessageId &id, const cabana::Signal *sig, const cabana::Signal &new_sig, QUndoCommand *parent = nullptr);
void undo() override;
void redo() override;
private:
const MessageId id;
Signal old_signal = {};
Signal new_signal = {};
cabana::Signal old_signal = {};
cabana::Signal new_signal = {};
};
namespace UndoStack {

77
tools/cabana/dbc.cc Normal file
View File

@ -0,0 +1,77 @@
#include "tools/cabana/dbc.h"
uint qHash(const MessageId &item) {
return qHash(item.source) ^ qHash(item.address);
}
std::vector<const cabana::Signal*> cabana::Msg::getSignals() const {
std::vector<const Signal*> ret;
ret.reserve(sigs.size());
for (auto &sig : sigs) ret.push_back(&sig);
std::sort(ret.begin(), ret.end(), [](auto l, auto r) { return l->start_bit < r->start_bit; });
return ret;
}
// helper functions
static QVector<int> BIG_ENDIAN_START_BITS = []() {
QVector<int> ret;
for (int i = 0; i < 64; i++)
for (int j = 7; j >= 0; j--)
ret.push_back(j + i * 8);
return ret;
}();
double get_raw_value(uint8_t *data, size_t data_size, const cabana::Signal &sig) {
int64_t val = 0;
int i = sig.msb / 8;
int bits = sig.size;
while (i >= 0 && i < data_size && bits > 0) {
int lsb = (int)(sig.lsb / 8) == i ? sig.lsb : i * 8;
int msb = (int)(sig.msb / 8) == i ? sig.msb : (i + 1) * 8 - 1;
int size = msb - lsb + 1;
uint64_t d = (data[i] >> (lsb - (i * 8))) & ((1ULL << size) - 1);
val |= d << (bits - size);
bits -= size;
i = sig.is_little_endian ? i - 1 : i + 1;
}
if (sig.is_signed) {
val -= ((val >> (sig.size - 1)) & 0x1) ? (1ULL << sig.size) : 0;
}
return val * sig.factor + sig.offset;
}
bool cabana::operator==(const cabana::Signal &l, const cabana::Signal &r) {
return l.name == r.name && l.size == r.size &&
l.start_bit == r.start_bit &&
l.msb == r.msb && l.lsb == r.lsb &&
l.is_signed == r.is_signed && l.is_little_endian == r.is_little_endian &&
l.factor == r.factor && l.offset == r.offset &&
l.min == r.min && l.max == r.max && l.comment == r.comment && l.unit == r.unit && l.val_desc == r.val_desc;
}
int bigEndianStartBitsIndex(int start_bit) { return BIG_ENDIAN_START_BITS[start_bit]; }
int bigEndianBitIndex(int index) { return BIG_ENDIAN_START_BITS.indexOf(index); }
void updateSigSizeParamsFromRange(cabana::Signal &s, int start_bit, int size) {
s.start_bit = s.is_little_endian ? start_bit : bigEndianBitIndex(start_bit);
s.size = size;
if (s.is_little_endian) {
s.lsb = s.start_bit;
s.msb = s.start_bit + s.size - 1;
} else {
s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1);
s.msb = s.start_bit;
}
}
std::pair<int, int> getSignalRange(const cabana::Signal *s) {
int from = s->is_little_endian ? s->start_bit : bigEndianBitIndex(s->start_bit);
int to = from + s->size - 1;
return {from, to};
}
std::vector<std::string> allDBCNames() { return get_dbc_names(); }

78
tools/cabana/dbc.h Normal file
View File

@ -0,0 +1,78 @@
#pragma once
#include <map>
#include <QList>
#include <QMetaType>
#include <QObject>
#include <QString>
#include "opendbc/can/common_dbc.h"
const QString UNTITLED = "untitled";
struct MessageId {
uint8_t source;
uint32_t address;
QString toString() const {
return QString("%1:%2").arg(source).arg(address, 1, 16);
}
bool operator==(const MessageId &other) const {
return source == other.source && address == other.address;
}
bool operator!=(const MessageId &other) const {
return !(*this == other);
}
bool operator<(const MessageId &other) const {
return std::pair{source, address} < std::pair{other.source, other.address};
}
bool operator>(const MessageId &other) const {
return std::pair{source, address} > std::pair{other.source, other.address};
}
};
uint qHash(const MessageId &item);
Q_DECLARE_METATYPE(MessageId);
typedef QList<std::pair<QString, QString>> ValueDescription;
namespace cabana {
struct Signal {
QString name;
int start_bit, msb, lsb, size;
bool is_signed;
double factor, offset;
bool is_little_endian;
QString min, max, unit;
QString comment;
ValueDescription val_desc;
};
struct Msg {
QString name;
uint32_t size;
QList<cabana::Signal> sigs;
std::vector<const cabana::Signal*> getSignals() const;
const cabana::Signal *sig(const QString &sig_name) const {
auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.name == sig_name; });
return it != sigs.end() ? &(*it) : nullptr;
}
};
bool operator==(const cabana::Signal &l, const cabana::Signal &r);
inline bool operator!=(const cabana::Signal &l, const cabana::Signal &r) { return !(l == r); }
}
// Helper functions
double get_raw_value(uint8_t *data, size_t data_size, const cabana::Signal &sig);
int bigEndianStartBitsIndex(int start_bit);
int bigEndianBitIndex(int index);
void updateSigSizeParamsFromRange(cabana::Signal &s, int start_bit, int size);
std::pair<int, int> getSignalRange(const cabana::Signal *s);
std::vector<std::string> allDBCNames();

View File

@ -8,8 +8,6 @@
#include <limits>
#include <sstream>
namespace dbcmanager {
bool DBCManager::open(const QString &dbc_file_name, QString *error) {
QString opendbc_file_path = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, dbc_file_name);
QFile file(opendbc_file_path);
@ -19,15 +17,49 @@ bool DBCManager::open(const QString &dbc_file_name, QString *error) {
return false;
}
bool DBCManager::open(const QString &name, const QString &content, QString *error) {
try {
std::istringstream stream(content.toStdString());
auto dbc = const_cast<DBC *>(dbc_parse_from_stream(name.toStdString(), stream));
msgs.clear();
for (auto &msg : dbc->msgs) {
auto &m = msgs[msg.address];
m.name = msg.name.c_str();
m.size = msg.size;
for (auto &s : msg.sigs) {
m.sigs.push_back({});
auto &sig = m.sigs.last();
sig.name = s.name.c_str();
sig.start_bit = s.start_bit;
sig.msb = s.msb;
sig.lsb = s.lsb;
sig.size = s.size;
sig.is_signed = s.is_signed;
sig.factor = s.factor;
sig.offset = s.offset;
sig.is_little_endian = s.is_little_endian;
}
}
parseExtraInfo(content);
name_ = name;
emit DBCFileChanged();
delete dbc;
} catch (std::exception &e) {
if (error) *error = e.what();
return false;
}
return true;
}
void DBCManager::parseExtraInfo(const QString &content) {
static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))");
static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))");
static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))");
static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"(.*)\";)");
static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (.*);)");
auto get_sig = [this](uint32_t address, const QString &name) -> Signal * {
auto m = (Msg *)msg(address);
return m ? (Signal *)m->sig(name) : nullptr;
auto get_sig = [this](uint32_t address, const QString &name) -> cabana::Signal * {
auto m = (cabana::Msg *)msg(address);
return m ? (cabana::Signal *)m->sig(name) : nullptr;
};
QTextStream stream((QString *)&content);
@ -119,17 +151,17 @@ void DBCManager::removeMsg(const MessageId &id) {
emit msgRemoved(id.address);
}
void DBCManager::addSignal(const MessageId &id, const Signal &sig) {
if (auto m = const_cast<Msg *>(msg(id.address))) {
void DBCManager::addSignal(const MessageId &id, const cabana::Signal &sig) {
if (auto m = const_cast<cabana::Msg *>(msg(id.address))) {
m->sigs.push_back(sig);
auto s = &m->sigs.last();
emit signalAdded(id.address, s);
}
}
void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig) {
if (auto m = const_cast<Msg *>(msg(id))) {
if (auto s = (Signal *)m->sig(sig_name)) {
void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig) {
if (auto m = const_cast<cabana::Msg *>(msg(id))) {
if (auto s = (cabana::Signal *)m->sig(sig_name)) {
*s = sig;
emit signalUpdated(s);
}
@ -137,7 +169,7 @@ void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, cons
}
void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) {
if (auto m = const_cast<Msg *>(msg(id))) {
if (auto m = const_cast<cabana::Msg *>(msg(id))) {
auto it = std::find_if(m->sigs.begin(), m->sigs.end(), [&](auto &s) { return s.name == sig_name; });
if (it != m->sigs.end()) {
emit signalRemoved(&(*it));
@ -151,117 +183,3 @@ DBCManager *dbc() {
return &dbc_manager;
}
// Msg
std::vector<const Signal*> Msg::getSignals() const {
std::vector<const Signal*> ret;
ret.reserve(sigs.size());
for (auto &sig : sigs) ret.push_back(&sig);
std::sort(ret.begin(), ret.end(), [](auto l, auto r) { return l->start_bit < r->start_bit; });
return ret;
}
// helper functions
static QVector<int> BIG_ENDIAN_START_BITS = []() {
QVector<int> ret;
for (int i = 0; i < 64; i++)
for (int j = 7; j >= 0; j--)
ret.push_back(j + i * 8);
return ret;
}();
int bigEndianStartBitsIndex(int start_bit) { return BIG_ENDIAN_START_BITS[start_bit]; }
int bigEndianBitIndex(int index) { return BIG_ENDIAN_START_BITS.indexOf(index); }
double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig) {
int64_t val = 0;
int i = sig.msb / 8;
int bits = sig.size;
while (i >= 0 && i < data_size && bits > 0) {
int lsb = (int)(sig.lsb / 8) == i ? sig.lsb : i * 8;
int msb = (int)(sig.msb / 8) == i ? sig.msb : (i + 1) * 8 - 1;
int size = msb - lsb + 1;
uint64_t d = (data[i] >> (lsb - (i * 8))) & ((1ULL << size) - 1);
val |= d << (bits - size);
bits -= size;
i = sig.is_little_endian ? i - 1 : i + 1;
}
if (sig.is_signed) {
val -= ((val >> (sig.size - 1)) & 0x1) ? (1ULL << sig.size) : 0;
}
return val * sig.factor + sig.offset;
}
void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size) {
s.start_bit = s.is_little_endian ? start_bit : bigEndianBitIndex(start_bit);
s.size = size;
if (s.is_little_endian) {
s.lsb = s.start_bit;
s.msb = s.start_bit + s.size - 1;
} else {
s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1);
s.msb = s.start_bit;
}
}
std::pair<int, int> getSignalRange(const Signal *s) {
int from = s->is_little_endian ? s->start_bit : bigEndianBitIndex(s->start_bit);
int to = from + s->size - 1;
return {from, to};
}
bool operator==(const Signal &l, const Signal &r) {
return l.name == r.name && l.size == r.size &&
l.start_bit == r.start_bit &&
l.msb == r.msb && l.lsb == r.lsb &&
l.is_signed == r.is_signed && l.is_little_endian == r.is_little_endian &&
l.factor == r.factor && l.offset == r.offset &&
l.min == r.min && l.max == r.max && l.comment == r.comment && l.unit == r.unit && l.val_desc == r.val_desc;
}
} // namespace dbcmanager
#include "opendbc/can/common_dbc.h"
std::vector<std::string> dbcmanager::DBCManager::allDBCNames() { return get_dbc_names(); }
bool dbcmanager::DBCManager::open(const QString &name, const QString &content, QString *error) {
try {
std::istringstream stream(content.toStdString());
auto dbc = const_cast<DBC *>(dbc_parse_from_stream(name.toStdString(), stream));
msgs.clear();
for (auto &msg : dbc->msgs) {
auto &m = msgs[msg.address];
m.name = msg.name.c_str();
m.size = msg.size;
for (auto &s : msg.sigs) {
m.sigs.push_back({});
auto &sig = m.sigs.last();
sig.name = s.name.c_str();
sig.start_bit = s.start_bit;
sig.msb = s.msb;
sig.lsb = s.lsb;
sig.size = s.size;
sig.is_signed = s.is_signed;
sig.factor = s.factor;
sig.offset = s.offset;
sig.is_little_endian = s.is_little_endian;
}
}
parseExtraInfo(content);
name_ = name;
emit DBCFileChanged();
delete dbc;
} catch (std::exception &e) {
if (error) *error = e.what();
return false;
}
return true;
}
uint qHash(const MessageId &item) {
return qHash(item.source) ^ qHash(item.address);
}

View File

@ -6,63 +6,7 @@
#include <QObject>
#include <QString>
struct MessageId {
uint8_t source;
uint32_t address;
QString toString() const {
return QString("%1:%2").arg(source).arg(address, 1, 16);
}
bool operator==(const MessageId &other) const {
return source == other.source && address == other.address;
}
bool operator!=(const MessageId &other) const {
return !(*this == other);
}
bool operator<(const MessageId &other) const {
return std::pair{source, address} < std::pair{other.source, other.address};
}
bool operator>(const MessageId &other) const {
return std::pair{source, address} > std::pair{other.source, other.address};
}
};
uint qHash(const MessageId &item);
Q_DECLARE_METATYPE(MessageId);
namespace dbcmanager {
typedef QList<std::pair<QString, QString>> ValueDescription;
struct Signal {
QString name;
int start_bit, msb, lsb, size;
bool is_signed;
double factor, offset;
bool is_little_endian;
QString min, max, unit;
QString comment;
ValueDescription val_desc;
};
struct Msg {
QString name;
uint32_t size;
std::vector<const Signal*> getSignals() const;
const Signal *sig(const QString &sig_name) const {
auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.name == sig_name; });
return it != sigs.end() ? &(*it) : nullptr;
}
private:
QList<Signal> sigs;
friend class DBCManager;
};
#include "tools/cabana/dbc.h"
class DBCManager : public QObject {
Q_OBJECT
@ -73,49 +17,37 @@ public:
bool open(const QString &dbc_file_name, QString *error = nullptr);
bool open(const QString &name, const QString &content, QString *error = nullptr);
QString generateDBC();
void addSignal(const MessageId &id, const Signal &sig);
void updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig);
void addSignal(const MessageId &id, const cabana::Signal &sig);
void updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig);
void removeSignal(const MessageId &id, const QString &sig_name);
static std::vector<std::string> allDBCNames();
inline QString name() const { return name_; }
void updateMsg(const MessageId &id, const QString &name, uint32_t size);
void removeMsg(const MessageId &id);
inline const std::map<uint32_t, Msg> &messages() const { return msgs; }
inline const Msg *msg(const MessageId &id) const { return msg(id.address); }
inline const Msg *msg(uint32_t address) const {
inline const std::map<uint32_t, cabana::Msg> &messages() const { return msgs; }
inline const cabana::Msg *msg(const MessageId &id) const { return msg(id.address); }
inline const cabana::Msg *msg(uint32_t address) const {
auto it = msgs.find(address);
return it != msgs.end() ? &it->second : nullptr;
}
signals:
void signalAdded(uint32_t address, const Signal *sig);
void signalRemoved(const Signal *sig);
void signalUpdated(const Signal *sig);
void signalAdded(uint32_t address, const cabana::Signal *sig);
void signalRemoved(const cabana::Signal *sig);
void signalUpdated(const cabana::Signal *sig);
void msgUpdated(uint32_t address);
void msgRemoved(uint32_t address);
void DBCFileChanged();
private:
void parseExtraInfo(const QString &content);
std::map<uint32_t, Msg> msgs;
std::map<uint32_t, cabana::Msg> msgs;
QString name_;
};
const QString UNTITLED = "untitled";
// TODO: Add helper function in dbc.h
double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig);
bool operator==(const Signal &l, const Signal &r);
inline bool operator!=(const Signal &l, const Signal &r) { return !(l == r); }
int bigEndianStartBitsIndex(int start_bit);
int bigEndianBitIndex(int index);
void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size);
std::pair<int, int> getSignalRange(const Signal *s);
DBCManager *dbc();
inline QString msgName(const MessageId &id) {
auto msg = dbc()->msg(id);
return msg ? msg->name : UNTITLED;
}
} // namespace dbcmanager

View File

@ -68,7 +68,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
QObject::connect(binary_view, &BinaryView::resizeSignal, signal_view->model, &SignalModel::resizeSignal);
QObject::connect(binary_view, &BinaryView::addSignal, signal_view->model, &SignalModel::addSignal);
QObject::connect(binary_view, &BinaryView::signalHovered, signal_view, &SignalView::signalHovered);
QObject::connect(binary_view, &BinaryView::signalClicked, [this](const Signal *s) { signal_view->selectSignal(s, true); });
QObject::connect(binary_view, &BinaryView::signalClicked, [this](const cabana::Signal *s) { signal_view->selectSignal(s, true); });
QObject::connect(binary_view, &BinaryView::editSignal, signal_view->model, &SignalModel::saveSignal);
QObject::connect(binary_view, &BinaryView::removeSignal, signal_view->model, &SignalModel::removeSignal);
QObject::connect(binary_view, &BinaryView::showChart, charts, &ChartsWidget::showChart);

View File

@ -11,8 +11,6 @@
#include "tools/cabana/streams/abstractstream.h"
#include "tools/cabana/util.h"
using namespace dbcmanager;
class HeaderView : public QHeaderView {
public:
HeaderView(Qt::Orientation orientation, QWidget *parent = nullptr) : QHeaderView(orientation, parent) {}
@ -64,7 +62,7 @@ public:
uint64_t last_fetch_time = 0;
std::function<bool(double, double)> filter_cmp = nullptr;
std::deque<Message> messages;
std::vector<const Signal *> sigs;
std::vector<const cabana::Signal *> sigs;
bool dynamic_mode = true;
bool display_signals_mode = true;
};

View File

@ -97,7 +97,7 @@ void MainWindow::createActions() {
file_menu->addSeparator();
QMenu *load_opendbc_menu = file_menu->addMenu(tr("Load DBC from commaai/opendbc"));
// load_opendbc_menu->setStyleSheet("QMenu { menu-scrollable: true; }");
auto dbc_names = dbc()->allDBCNames();
auto dbc_names = allDBCNames();
std::sort(dbc_names.begin(), dbc_names.end());
for (const auto &name : dbc_names) {
load_opendbc_menu->addAction(QString::fromStdString(name), this, &MainWindow::openOpendbcFile);

View File

@ -8,7 +8,6 @@
#include "tools/cabana/dbcmanager.h"
#include "tools/cabana/streams/abstractstream.h"
using namespace dbcmanager;
class MessageListModel : public QAbstractTableModel {
Q_OBJECT

View File

@ -22,7 +22,7 @@ SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(p
QObject::connect(can, &AbstractStream::msgsReceived, this, &SignalModel::updateState);
}
void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const Signal *sig) {
void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const cabana::Signal *sig) {
Item *item = new Item{.sig = sig, .parent = parent_item, .title = sig->name, .type = Item::Sig};
parent_item->children.insert(pos, item);
QString titles[]{"Name", "Size", "Little Endian", "Signed", "Offset", "Factor", "Extra Info", "Unit", "Comment", "Minimum Value", "Maximum Value", "Value Descriptions"};
@ -104,7 +104,7 @@ Qt::ItemFlags SignalModel::flags(const QModelIndex &index) const {
return flags;
}
int SignalModel::signalRow(const Signal *sig) const {
int SignalModel::signalRow(const cabana::Signal *sig) const {
for (int i = 0; i < root->children.size(); ++i) {
if (root->children[i]->sig == sig) return i;
}
@ -168,7 +168,7 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r
if (role != Qt::EditRole && role != Qt::CheckStateRole) return false;
Item *item = getItem(index);
Signal s = *item->sig;
cabana::Signal s = *item->sig;
switch (item->type) {
case Item::Name: s.name = value.toString(); break;
case Item::Size: s.size = value.toInt(); break;
@ -203,7 +203,7 @@ void SignalModel::showExtraInfo(const QModelIndex &index) {
}
}
bool SignalModel::saveSignal(const Signal *origin_s, Signal &s) {
bool SignalModel::saveSignal(const cabana::Signal *origin_s, cabana::Signal &s) {
auto msg = dbc()->msg(msg_id);
if (s.name != origin_s->name && msg->sig(s.name) != nullptr) {
QString text = tr("There is already a signal with the same name '%1'").arg(s.name);
@ -243,7 +243,7 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) {
}
}
Signal sig = {.is_little_endian = little_endian, .factor = 1};
cabana::Signal sig = {.is_little_endian = little_endian, .factor = 1};
for (int i = 1; /**/; ++i) {
sig.name = QString("NEW_SIGNAL_%1").arg(i);
if (msg->sig(sig.name) == nullptr) break;
@ -252,13 +252,13 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) {
UndoStack::push(new AddSigCommand(msg_id, sig));
}
void SignalModel::resizeSignal(const Signal *sig, int start_bit, int size) {
Signal s = *sig;
void SignalModel::resizeSignal(const cabana::Signal *sig, int start_bit, int size) {
cabana::Signal s = *sig;
updateSigSizeParamsFromRange(s, start_bit, size);
saveSignal(sig, s);
}
void SignalModel::removeSignal(const Signal *sig) {
void SignalModel::removeSignal(const cabana::Signal *sig) {
UndoStack::push(new RemoveSigCommand(msg_id, sig));
}
@ -268,7 +268,7 @@ void SignalModel::handleMsgChanged(uint32_t address) {
}
}
void SignalModel::handleSignalAdded(uint32_t address, const Signal *sig) {
void SignalModel::handleSignalAdded(uint32_t address, const cabana::Signal *sig) {
if (address == msg_id.address) {
int i = 0;
for (; i < root->children.size(); ++i) {
@ -280,13 +280,13 @@ void SignalModel::handleSignalAdded(uint32_t address, const Signal *sig) {
}
}
void SignalModel::handleSignalUpdated(const Signal *sig) {
void SignalModel::handleSignalUpdated(const cabana::Signal *sig) {
if (int row = signalRow(sig); row != -1) {
emit dataChanged(index(row, 0), index(row, 1), {Qt::DisplayRole, Qt::EditRole, Qt::CheckStateRole});
}
}
void SignalModel::handleSignalRemoved(const Signal *sig) {
void SignalModel::handleSignalRemoved(const cabana::Signal *sig) {
if (int row = signalRow(sig); row != -1) {
beginRemoveRows({}, row, row);
delete root->children.takeAt(row);
@ -431,7 +431,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts),
QObject::connect(model, &QAbstractItemModel::modelReset, this, &SignalView::rowsChanged);
QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &SignalView::rowsChanged);
QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &SignalView::rowsChanged);
QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const Signal *sig) { selectSignal(sig); });
QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const cabana::Signal *sig) { selectSignal(sig); });
setWhatsThis(tr(R"(
<b>Signal view</b><br />
@ -485,7 +485,7 @@ void SignalView::rowClicked(const QModelIndex &index) {
}
}
void SignalView::selectSignal(const Signal *sig, bool expand) {
void SignalView::selectSignal(const cabana::Signal *sig, bool expand) {
if (int row = model->signalRow(sig); row != -1) {
auto idx = model->index(row, 0);
if (expand) {
@ -509,7 +509,7 @@ void SignalView::updateChartState() {
}
}
void SignalView::signalHovered(const Signal *sig) {
void SignalView::signalHovered(const cabana::Signal *sig) {
auto &children = model->root->children;
for (int i = 0; i < children.size(); ++i) {
bool highlight = children[i]->sig == sig;

View File

@ -21,7 +21,7 @@ public:
Item *parent = nullptr;
QList<Item *> children;
const Signal *sig = nullptr;
const cabana::Signal *sig = nullptr;
QString title;
bool highlight = false;
bool extra_expanded = false;
@ -39,18 +39,18 @@ public:
void setMessage(const MessageId &id);
void setFilter(const QString &txt);
void addSignal(int start_bit, int size, bool little_endian);
bool saveSignal(const Signal *origin_s, Signal &s);
void resizeSignal(const Signal *sig, int start_bit, int size);
void removeSignal(const Signal *sig);
bool saveSignal(const cabana::Signal *origin_s, cabana::Signal &s);
void resizeSignal(const cabana::Signal *sig, int start_bit, int size);
void removeSignal(const cabana::Signal *sig);
Item *getItem(const QModelIndex &index) const;
int signalRow(const Signal *sig) const;
int signalRow(const cabana::Signal *sig) const;
void showExtraInfo(const QModelIndex &index);
private:
void insertItem(SignalModel::Item *parent_item, int pos, const Signal *sig);
void handleSignalAdded(uint32_t address, const Signal *sig);
void handleSignalUpdated(const Signal *sig);
void handleSignalRemoved(const Signal *sig);
void insertItem(SignalModel::Item *parent_item, int pos, const cabana::Signal *sig);
void handleSignalAdded(uint32_t address, const cabana::Signal *sig);
void handleSignalUpdated(const cabana::Signal *sig);
void handleSignalRemoved(const cabana::Signal *sig);
void handleMsgChanged(uint32_t address);
void refresh();
void updateState(const QHash<MessageId, CanData> *msgs);
@ -94,15 +94,15 @@ class SignalView : public QFrame {
public:
SignalView(ChartsWidget *charts, QWidget *parent);
void setMessage(const MessageId &id);
void signalHovered(const Signal *sig);
void signalHovered(const cabana::Signal *sig);
void updateChartState();
void selectSignal(const Signal *sig, bool expand = false);
void selectSignal(const cabana::Signal *sig, bool expand = false);
void rowClicked(const QModelIndex &index);
SignalModel *model = nullptr;
signals:
void highlight(const Signal *sig);
void showChart(const MessageId &id, const Signal *sig, bool show, bool merge);
void highlight(const cabana::Signal *sig);
void showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge);
private:
void rowsChanged();

View File

@ -5,7 +5,6 @@
#include "tools/replay/logreader.h"
#include "tools/cabana/dbcmanager.h"
#include "tools/cabana/streams/abstractstream.h"
using namespace dbcmanager;
// demo route, first segment
const std::string TEST_RLOG_URL = "https://commadata2.blob.core.windows.net/commadata2/4cf7a6ad03080c90/2021-09-29--13-46-36/0/rlog.bz2";

View File

@ -9,7 +9,6 @@
#include "tools/cabana/dbcmanager.h"
#include "tools/cabana/streams/abstractstream.h"
using namespace dbcmanager;
FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::WindowFlags() | Qt::Window) {
setWindowTitle(tr("Find similar bits"));

View File

@ -7,7 +7,6 @@
#include <QTableWidget>
#include "tools/cabana/dbcmanager.h"
using namespace dbcmanager;
class FindSimilarBitsDlg : public QDialog {
Q_OBJECT

View File

@ -128,7 +128,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
}
}
QColor getColor(const Signal *sig) {
QColor getColor(const cabana::Signal *sig) {
float h = 19 * (float)sig->lsb / 64.0;
h = fmod(h, 1.0);

View File

@ -11,8 +11,7 @@
#include <QToolButton>
#include <QVector>
#include "tools/cabana/dbcmanager.h"
using namespace dbcmanager;
#include "tools/cabana/dbc.h"
class ChangeTracker {
public:
@ -59,7 +58,7 @@ public:
inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); }
QString toHex(uint8_t byte);
QColor getColor(const dbcmanager::Signal *sig);
QColor getColor(const cabana::Signal *sig);
class NameValidator : public QRegExpValidator {
Q_OBJECT

View File

@ -13,7 +13,6 @@
#include "selfdrive/ui/qt/widgets/controls.h"
#include "tools/cabana/dbcmanager.h"
#include "tools/cabana/streams/abstractstream.h"
using namespace dbcmanager;
class Slider : public QSlider {
Q_OBJECT