From ac0dbf74bc835faa46beab4bbb948c95597e4e67 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Feb 2023 11:31:54 +0800 Subject: [PATCH] cabana: add support for load&save extra dbc info (#27203) * support extra info * support undo/redo * fix undo/redo * cleanup * fix regexp * refactor dbcmanager * replace text in headerview * fix binary::refresh * cleanup * use QRegularExpression * add desc validation * edit val description in table * cleanup --- tools/cabana/SConscript | 2 + tools/cabana/binaryview.cc | 21 ++- tools/cabana/binaryview.h | 3 +- tools/cabana/chartswidget.cc | 8 +- tools/cabana/chartswidget.h | 2 +- tools/cabana/commands.cc | 16 +- tools/cabana/commands.h | 4 +- tools/cabana/dbcmanager.cc | 218 +++++++++++++++++--------- tools/cabana/dbcmanager.h | 56 ++++--- tools/cabana/detailwidget.cc | 6 +- tools/cabana/historylog.cc | 19 +-- tools/cabana/historylog.h | 3 +- tools/cabana/messageswidget.cc | 6 +- tools/cabana/messageswidget.h | 2 + tools/cabana/signaledit.cc | 122 ++++++++++++-- tools/cabana/signaledit.h | 18 ++- tools/cabana/streams/replaystream.cc | 2 - tools/cabana/streams/replaystream.h | 1 - tools/cabana/tests/test_cabana.cc | 19 ++- tools/cabana/tools/findsimilarbits.cc | 1 + tools/cabana/tools/findsimilarbits.h | 1 + tools/cabana/util.cc | 2 +- tools/cabana/util.h | 6 +- tools/cabana/videowidget.h | 2 + 24 files changed, 375 insertions(+), 165 deletions(-) diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index a9922ba9be..166b3d5548 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -17,6 +17,8 @@ qt_libs = ['qt_util'] + base_libs cabana_libs = [widgets, cereal, messaging, visionipc, replay_lib, opendbc,'avutil', 'avcodec', 'avformat', 'bz2', 'curl', 'yuv'] + qt_libs cabana_env = qt_env.Clone() +opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % (cabana_env.Dir("../../opendbc").abspath) +cabana_env['CXXFLAGS'] += [opendbc_path] prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 20edfd06ff..5ea5ea2d99 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -12,7 +12,6 @@ #include "tools/cabana/commands.h" #include "tools/cabana/signaledit.h" -#include "tools/cabana/streams/abstractstream.h" // BinaryView @@ -170,7 +169,7 @@ void BinaryView::highlightPosition(const QPoint &pos) { auto item = (BinaryViewModel::Item *)index.internalPointer(); const Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back(); highlight(sig); - QToolTip::showText(pos, sig ? sig->name.c_str() : "", this, rect()); + QToolTip::showText(pos, sig ? sig->name : "", this, rect()); } } @@ -246,22 +245,22 @@ std::tuple BinaryView::getSelection(QModelIndex index) { void BinaryViewModel::refresh() { beginResetModel(); items.clear(); - if ((dbc_msg = dbc()->msg(*msg_id))) { + if (auto dbc_msg = dbc()->msg(*msg_id)) { row_count = dbc_msg->size; items.resize(row_count * column_count); - for (auto sig : dbc_msg->getSignals()) { - auto [start, end] = getSignalRange(sig); + for (auto &sig : dbc_msg->sigs) { + auto [start, end] = getSignalRange(&sig); for (int j = start; j <= end; ++j) { - int bit_index = sig->is_little_endian ? bigEndianBitIndex(j) : j; + int bit_index = sig.is_little_endian ? bigEndianBitIndex(j) : j; int idx = column_count * (bit_index / 8) + bit_index % 8; if (idx >= items.size()) { - qWarning() << "signal " << sig->name.c_str() << "out of bounds.start_bit:" << sig->start_bit << "size:" << sig->size; + qWarning() << "signal " << sig.name << "out of bounds.start_bit:" << sig.start_bit << "size:" << sig.size; break; } - if (j == start) sig->is_little_endian ? items[idx].is_lsb = true : items[idx].is_msb = true; - if (j == end) sig->is_little_endian ? items[idx].is_msb = true : items[idx].is_lsb = true; - items[idx].bg_color = getColor(sig); - items[idx].sigs.push_back(sig); + if (j == start) sig.is_little_endian ? items[idx].is_lsb = true : items[idx].is_msb = true; + if (j == end) sig.is_little_endian ? items[idx].is_msb = true : items[idx].is_lsb = true; + items[idx].bg_color = getColor(&sig); + items[idx].sigs.push_back(&sig); } } } else { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 6743b6cfac..1d6d5d0b07 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -9,6 +9,8 @@ #include #include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; class BinaryItemDelegate : public QStyledItemDelegate { public: @@ -49,7 +51,6 @@ public: std::vector items; std::optional msg_id; - const DBCMsg *dbc_msg = nullptr; int row_count = 0; const int column_count = 9; }; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 9c5ed097c6..8515ffcfe7 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -459,7 +459,7 @@ void ChartView::updateTitle() { } for (auto &s : sigs) { auto decoration = s.series->isVisible() ? "none" : "line-through"; - s.series->setName(QString("%2 %3 %4").arg(decoration, s.sig->name.c_str(), msgName(s.msg_id), s.msg_id.toString())); + s.series->setName(QString("%2 %3 %4").arg(decoration, s.sig->name, msgName(s.msg_id), s.msg_id.toString())); } } @@ -672,7 +672,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { value = QString::number(it->y()); track_pts[i] = chart()->mapToPosition(*it); } - text_list.push_back(QString("%2: %3").arg(sigs[i].series->color().name(), sigs[i].sig->name.c_str(), value)); + text_list.push_back(QString("%2: %3").arg(sigs[i].series->color().name(), sigs[i].sig->name, value)); } auto max = std::max_element(track_pts.begin(), track_pts.end(), [](auto &a, auto &b) { return a.x() < b.x(); }); auto pt = (max == track_pts.end()) ? ev->pos() : *max; @@ -887,7 +887,7 @@ void SeriesSelector::updateAvailableList(int index) { available_list->clear(); MessageId msg_id = msgs_combo->itemData(index).value(); auto selected_items = seletedItems(); - for (auto &[name, s] : dbc()->msg(msg_id)->sigs) { + for (auto &s : dbc()->msg(msg_id)->sigs) { bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), [=, sig=&s](auto it) { return it->msg_id == msg_id && it->sig == sig; }); if (!is_selected) { addItemToList(available_list, msg_id, &s); @@ -896,7 +896,7 @@ void SeriesSelector::updateAvailableList(int index) { } void SeriesSelector::addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name) { - QString text = QString(" %1").arg(getColor(sig).name(), sig->name.c_str()); + QString text = QString(" %1").arg(getColor(sig).name(), sig->name); if (show_msg_name) text += QString(" %0 %1").arg(msgName(id), id.toString()); QLabel *label = new QLabel(text); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 7569155d39..7089b4eaee 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -15,7 +15,7 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" - +using namespace dbcmanager; using namespace QtCharts; const int CHART_MIN_WIDTH = 300; diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc index b03f46b5d2..e03d6d1b11 100644 --- a/tools/cabana/commands.cc +++ b/tools/cabana/commands.cc @@ -36,7 +36,7 @@ RemoveMsgCommand::RemoveMsgCommand(const MessageId &id, QUndoCommand *parent) : void RemoveMsgCommand::undo() { if (!message.name.isEmpty()) { dbc()->updateMsg(id, message.name, message.size); - for (auto &[name, s] : message.sigs) + for (auto &s : message.sigs) dbc()->addSignal(id, s); } } @@ -50,31 +50,31 @@ void RemoveMsgCommand::redo() { AddSigCommand::AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent) : id(id), signal(sig), QUndoCommand(parent) { - setText(QObject::tr("Add signal %1 to %2").arg(sig.name.c_str()).arg(id.address)); + setText(QObject::tr("Add signal %1 to %2").arg(sig.name).arg(id.address)); } -void AddSigCommand::undo() { dbc()->removeSignal(id, signal.name.c_str()); } +void AddSigCommand::undo() { dbc()->removeSignal(id, signal.name); } void AddSigCommand::redo() { dbc()->addSignal(id, signal); } // RemoveSigCommand RemoveSigCommand::RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent) : id(id), signal(*sig), QUndoCommand(parent) { - setText(QObject::tr("Remove signal %1 from %2").arg(signal.name.c_str()).arg(id.address)); + setText(QObject::tr("Remove signal %1 from %2").arg(signal.name).arg(id.address)); } void RemoveSigCommand::undo() { dbc()->addSignal(id, signal); } -void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name.c_str()); } +void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name); } // EditSignalCommand EditSignalCommand::EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent) : id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) { - setText(QObject::tr("Edit signal %1").arg(old_signal.name.c_str())); + setText(QObject::tr("Edit signal %1").arg(old_signal.name)); } -void EditSignalCommand::undo() { dbc()->updateSignal(id, new_signal.name.c_str(), old_signal); } -void EditSignalCommand::redo() { dbc()->updateSignal(id, old_signal.name.c_str(), new_signal); } +void EditSignalCommand::undo() { dbc()->updateSignal(id, new_signal.name, old_signal); } +void EditSignalCommand::redo() { dbc()->updateSignal(id, old_signal.name, new_signal); } namespace UndoStack { diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index 46e9f0a030..57df664974 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -4,6 +4,8 @@ #include #include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; class EditMsgCommand : public QUndoCommand { public: @@ -25,7 +27,7 @@ public: private: const MessageId id; - DBCMsg message; + Msg message; }; class AddSigCommand : public QUndoCommand { diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 27f16c71e5..ae3a65a99b 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -1,63 +1,114 @@ #include "tools/cabana/dbcmanager.h" +#include +#include +#include +#include +#include #include #include -#include -uint qHash(const MessageId &item) { - return qHash(item.source) ^ qHash(item.address); -} +namespace dbcmanager { -DBCManager::DBCManager(QObject *parent) : QObject(parent) {} - -DBCManager::~DBCManager() {} - -void DBCManager::open(const QString &dbc_file_name) { - dbc = const_cast(dbc_lookup(dbc_file_name.toStdString())); - initMsgMap(); +void sortSignalsByAddress(QList &sigs) { + std::sort(sigs.begin(), sigs.end(), [](auto &a, auto &b) { return a.start_bit < b.start_bit; }); } -bool DBCManager::open(const QString &name, const QString &content, QString *error) { - try { - std::istringstream stream(content.toStdString()); - dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); - initMsgMap(); - return true; - } catch (std::exception &e) { - if (error) *error = e.what(); +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); + if (file.open(QIODevice::ReadOnly)) { + return open(dbc_file_name, file.readAll(), error); } return false; } -void DBCManager::initMsgMap() { - 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[QString::fromStdString(s.name)] = s; +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; + }; + + QTextStream stream((QString *)&content); + uint32_t address = 0; + while (!stream.atEnd()) { + QString line = stream.readLine().trimmed(); + if (line.startsWith("BO_ ")) { + if (auto match = bo_regexp.match(line); match.hasMatch()) { + address = match.captured(1).toUInt(); + } + } else if (line.startsWith("SG_ ")) { + int offset = 0; + auto match = sg_regexp.match(line); + if (!match.hasMatch()) { + match = sgm_regexp.match(line); + offset = 1; + } + if (match.hasMatch()) { + if (auto s = get_sig(address, match.captured(1))) { + s->min = match.captured(8 + offset); + s->max = match.captured(9 + offset); + s->unit = match.captured(10 + offset); + } + } + } else if (line.startsWith("VAL_ ")) { + if (auto match = val_regexp.match(line); match.hasMatch()) { + if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { + QStringList desc_list = match.captured(3).trimmed().split('"'); + for (int i = 0; i < desc_list.size(); i += 2) { + auto val = desc_list[i].trimmed(); + if (!val.isEmpty() && (i + 1) < desc_list.size()) { + auto desc = desc_list[i+1].trimmed(); + s->val_desc.push_back({val, desc}); + } + } + } + } + } else if (line.startsWith("CM_ SG_ ")) { + if (auto match = sg_comment_regexp.match(line); match.hasMatch()) { + if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { + s->comment = match.captured(3).trimmed(); + } + } + } } - emit DBCFileChanged(); } QString DBCManager::generateDBC() { - QString dbc_string; + QString dbc_string, signal_comment, val_desc; for (auto &[address, m] : msgs) { dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(address).arg(m.name).arg(m.size); - for (auto &[name, sig] : m.sigs) { - dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [0|0] \"\" XXX\n") - .arg(name) + for (auto &sig : m.sigs) { + dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [%8|%9] \"%10\" XXX\n") + .arg(sig.name) .arg(sig.start_bit) .arg(sig.size) .arg(sig.is_little_endian ? '1' : '0') .arg(sig.is_signed ? '-' : '+') .arg(sig.factor, 0, 'g', std::numeric_limits::digits10) - .arg(sig.offset, 0, 'g', std::numeric_limits::digits10); + .arg(sig.offset, 0, 'g', std::numeric_limits::digits10) + .arg(sig.min) + .arg(sig.max) + .arg(sig.unit); + if (!sig.comment.isEmpty()) { + signal_comment += QString("CM_ SG_ %1 %2 \"%3\";\n").arg(address).arg(sig.name).arg(sig.comment); + } + if (!sig.val_desc.isEmpty()) { + QString text; + for (auto &[val, desc] : sig.val_desc) { + text += QString("%1 \"%2\"").arg(val, desc); + } + val_desc += QString("VAL_ %1 %2 %3;\n").arg(address).arg(sig.name).arg(text); + } } dbc_string += "\n"; } - return dbc_string; + return dbc_string + signal_comment + val_desc; } void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size) { @@ -73,31 +124,29 @@ void DBCManager::removeMsg(const MessageId &id) { } void DBCManager::addSignal(const MessageId &id, const Signal &sig) { - if (auto m = const_cast(msg(id.address))) { - auto &s = m->sigs[sig.name.c_str()]; - s = sig; - emit signalAdded(id.address, &s); + if (auto m = const_cast(msg(id.address))) { + m->sigs.push_back(sig); + auto s = &m->sigs.last(); + sortSignalsByAddress(m->sigs); + emit signalAdded(id.address, s); } } void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig) { - if (auto m = const_cast(msg(id))) { - // change key name - QString new_name = QString::fromStdString(sig.name); - auto node = m->sigs.extract(sig_name); - node.key() = new_name; - auto it = m->sigs.insert(std::move(node)); - auto &s = m->sigs[new_name]; - s = sig; - emit signalUpdated(&s); + if (auto m = const_cast(msg(id))) { + if (auto s = (Signal *)m->sig(sig_name)) { + *s = sig; + sortSignalsByAddress(m->sigs); + emit signalUpdated(s); + } } } void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) { - if (auto m = const_cast(msg(id))) { - auto it = m->sigs.find(sig_name); + if (auto m = const_cast(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->second)); + emit signalRemoved(&(*it)); m->sigs.erase(it); } } @@ -108,16 +157,6 @@ DBCManager *dbc() { return &dbc_manager; } -// DBCMsg - -std::vector DBCMsg::getSignals() const { - std::vector 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 BIG_ENDIAN_START_BITS = []() { @@ -128,13 +167,8 @@ static QVector BIG_ENDIAN_START_BITS = []() { 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); -} +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; @@ -155,8 +189,7 @@ double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig) { if (sig.is_signed) { val -= ((val >> (sig.size - 1)) & 0x1) ? (1ULL << sig.size) : 0; } - double value = val * sig.factor + sig.offset; - return value; + return val * sig.factor + sig.offset; } void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size) { @@ -182,5 +215,50 @@ bool operator==(const Signal &l, const Signal &r) { 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.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 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_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; + } + sortSignalsByAddress(m.sigs); + } + 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); } diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index b766c837b6..b438b3e1c2 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -1,9 +1,8 @@ #pragma once #include -#include +#include #include -#include "opendbc/can/common_dbc.h" struct MessageId { uint8_t source; @@ -30,40 +29,55 @@ struct MessageId { } }; +uint qHash(const MessageId &item); Q_DECLARE_METATYPE(MessageId); -uint qHash(const MessageId &item); +namespace dbcmanager { + +typedef QList> 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 DBCMsg { +struct Msg { QString name; uint32_t size; - // signal must be saved as value in map to make undo stack work properly. - std::map sigs; - // return vector, sort by start_bits - std::vector getSignals() const; + QList sigs; + + 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; + } }; class DBCManager : public QObject { Q_OBJECT public: - DBCManager(QObject *parent); - ~DBCManager(); - - void open(const QString &dbc_file_name); + DBCManager(QObject *parent) {} + ~DBCManager() {} + 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 removeSignal(const MessageId &id, const QString &sig_name); - inline static std::vector allDBCNames() { return get_dbc_names(); } - inline QString name() const { return dbc ? dbc->name.c_str() : ""; } + static std::vector 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 &messages() const { return msgs; } - inline const DBCMsg *msg(const MessageId &id) const { return msg(id.address); } - inline const DBCMsg *msg(uint32_t address) const { + inline const std::map &messages() const { return msgs; } + inline const Msg *msg(const MessageId &id) const { return msg(id.address); } + inline const Msg *msg(uint32_t address) const { auto it = msgs.find(address); return it != msgs.end() ? &it->second : nullptr; } @@ -77,9 +91,9 @@ signals: void DBCFileChanged(); private: - void initMsgMap(); - DBC *dbc = nullptr; - std::map msgs; + void parseExtraInfo(const QString &content); + std::map msgs; + QString name_; }; const QString UNTITLED = "untitled"; @@ -97,3 +111,5 @@ inline QString msgName(const MessageId &id) { auto msg = dbc()->msg(id); return msg ? msg->name : UNTITLED; } + +} // namespace dbcmanager diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index f290b3b706..882ea932c6 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -6,8 +6,6 @@ #include #include "tools/cabana/commands.h" -#include "tools/cabana/dbcmanager.h" -#include "tools/cabana/streams/abstractstream.h" // DetailWidget @@ -153,13 +151,13 @@ void DetailWidget::refresh() { if (!msg_id) return; QStringList warnings; - const DBCMsg *msg = dbc()->msg(*msg_id); + auto msg = dbc()->msg(*msg_id); if (msg) { if (msg->size != can->lastMessage(*msg_id).dat.size()) { warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); } for (auto s : binary_view->getOverlappingSignals()) { - warnings.push_back(tr("%1 has overlapping bits.").arg(s->name.c_str())); + warnings.push_back(tr("%1 has overlapping bits.").arg(s->name)); } } else { warnings.push_back(tr("Drag-Select in binary view to create new signal.")); diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 87968d495c..a1c671b68d 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -5,6 +5,7 @@ #include #include "tools/cabana/commands.h" +#include "tools/cabana/util.h" // HistoryLogModel @@ -30,7 +31,7 @@ void HistoryLogModel::refresh() { beginResetModel(); sigs.clear(); if (auto dbc_msg = dbc()->msg(*msg_id)) { - sigs = dbc_msg->getSignals(); + sigs = dbc_msg->sigs; } last_fetch_time = 0; has_more_data = true; @@ -47,9 +48,9 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i if (section == 0) { return "Time"; } - return show_signals ? QString::fromStdString(sigs[section - 1]->name).replace('_', ' ') : "Data"; + return show_signals ? sigs[section - 1].name : "Data"; } else if (role == Qt::BackgroundRole && section > 0 && show_signals) { - return QBrush(getColor(sigs[section - 1])); + return QBrush(getColor(&sigs[section - 1])); } } return {}; @@ -113,7 +114,7 @@ std::deque HistoryLogModel::fetchData(InputIt first, I if (msg_id->address == c.getAddress() && msg_id->source == c.getSrc()) { const auto dat = c.getDat(); for (int i = 0; i < sigs.size(); ++i) { - values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *(sigs[i])); + values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), sigs[i]); } if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { auto &m = msgs.emplace_back(); @@ -170,8 +171,8 @@ QSize HeaderView::sectionSizeFromContents(int logicalIndex) const { return time_col_size; } else { int default_size = qMax(100, (rect().width() - time_col_size.width()) / (model()->columnCount() - 1)); - const QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString(); - const QRect rect = fontMetrics().boundingRect({0, 0, default_size, 2000}, defaultAlignment(), text); + QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString(); + const QRect rect = fontMetrics().boundingRect({0, 0, default_size, 2000}, defaultAlignment(), text.replace(QChar('_'), ' ')); QSize size = rect.size() + QSize{10, 6}; return QSize{qMax(size.width(), default_size), size.height()}; } @@ -183,7 +184,7 @@ void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalI painter->fillRect(rect, bg_role.value()); } QString text = model()->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString(); - painter->drawText(rect.adjusted(5, 3, -5, -3), defaultAlignment(), text); + painter->drawText(rect.adjusted(5, 3, -5, -3), defaultAlignment(), text.replace(QChar('_'), ' ')); } // LogsWidget @@ -253,8 +254,8 @@ void LogsWidget::refresh() { bool has_signal = model->sigs.size(); if (has_signal) { signals_cb->clear(); - for (auto s : model->sigs) { - signals_cb->addItem(s->name.c_str()); + for (auto &s : model->sigs) { + signals_cb->addItem(s.name); } } value_edit->clear(); diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 00a8f73836..a1b7bc0098 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -11,6 +11,7 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; class HeaderView : public QHeaderView { public: @@ -63,7 +64,7 @@ public: uint64_t last_fetch_time = 0; std::function filter_cmp = nullptr; std::deque messages; - std::vector sigs; + QList sigs; bool dynamic_mode = true; bool display_signals_mode = true; }; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 81ebc6af20..42ac22865c 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -7,8 +7,6 @@ #include #include -#include "tools/cabana/dbcmanager.h" - MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); @@ -140,8 +138,8 @@ void MessageListModel::setFilterString(const QString &string) { 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 &signal : msg->getSignals()) { - if (QString::fromStdString(signal->name).contains(txt, cs)) return true; + for (auto &signal : msg->sigs) { + if (signal.name.contains(txt, cs)) return true; } } return false; diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 562069c3ae..d88def3acb 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -9,7 +9,9 @@ #include #include +#include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; class MessageListModel : public QAbstractTableModel { Q_OBJECT diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index e2be5c85d0..d5099da6f4 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -1,5 +1,6 @@ #include "tools/cabana/signaledit.h" +#include #include #include #include @@ -23,9 +24,9 @@ SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(p } void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const Signal *sig) { - Item *item = new Item{.sig = sig, .parent = parent_item, .title = sig->name.c_str(), .type = Item::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", "Maximum", "Description"}; + QString titles[]{"Name", "Size", "Little Endian", "Signed", "Offset", "Factor", "Extra Info", "Unit", "Comment", "Minimum Value", "Maximum Value", "Value Descriptions"}; for (int i = 0; i < std::size(titles); ++i) { item->children.push_back(new Item{.sig = sig, .parent = item, .title = titles[i], .type = (Item::Type)(i + Item::Name)}); } @@ -47,9 +48,9 @@ void SignalModel::refresh() { beginResetModel(); root.reset(new SignalModel::Item); if (auto msg = dbc()->msg(msg_id)) { - for (auto &s : msg->getSignals()) { - if (filter_str.isEmpty() || QString::fromStdString(s->name).contains(filter_str, Qt::CaseInsensitive)) { - insertItem(root.get(), root->children.size(), s); + for (auto &s : msg->sigs) { + if (filter_str.isEmpty() || s.name.contains(filter_str, Qt::CaseInsensitive)) { + insertItem(root.get(), root->children.size(), &s); } } } @@ -115,14 +116,25 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { const Item *item = getItem(index); if (role == Qt::DisplayRole || role == Qt::EditRole) { if (index.column() == 0) { - return item->type == Item::Sig ? QString::fromStdString(item->sig->name) : item->title; + return item->type == Item::Sig ? item->sig->name : item->title; } else { switch (item->type) { case Item::Sig: return item->sig_val; - case Item::Name: return QString::fromStdString(item->sig->name); + case Item::Name: return item->sig->name; case Item::Size: return item->sig->size; case Item::Offset: return QString::number(item->sig->offset, 'f', 6); case Item::Factor: return QString::number(item->sig->factor, 'f', 6); + case Item::Unit: return item->sig->unit; + case Item::Comment: return item->sig->comment; + case Item::Min: return item->sig->min; + case Item::Max: return item->sig->max; + case Item::Desc: { + QString val_desc; + for (auto &[val, desc] : item->sig->val_desc) { + val_desc += QString("%1 \"%2\"").arg(val, desc); + } + return val_desc; + } default: break; } } @@ -142,12 +154,17 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r Item *item = getItem(index); Signal s = *item->sig; switch (item->type) { - case Item::Name: s.name = value.toString().toStdString(); break; + case Item::Name: s.name = value.toString(); break; case Item::Size: s.size = value.toInt(); break; case Item::Endian: s.is_little_endian = value.toBool(); break; case Item::Signed: s.is_signed = value.toBool(); break; case Item::Offset: s.offset = value.toDouble(); break; case Item::Factor: s.factor = value.toDouble(); break; + case Item::Unit: s.unit = value.toString(); break; + case Item::Comment: s.comment = value.toString(); break; + case Item::Min: s.min = value.toString(); break; + case Item::Max: s.max = value.toString(); break; + case Item::Desc: s.val_desc = value.value(); break; default: return false; } bool ret = saveSignal(item->sig, s); @@ -172,8 +189,8 @@ void SignalModel::showExtraInfo(const QModelIndex &index) { bool SignalModel::saveSignal(const Signal *origin_s, Signal &s) { auto msg = dbc()->msg(msg_id); - if (s.name != origin_s->name && msg->sigs.count(s.name.c_str()) != 0) { - QString text = tr("There is already a signal with the same name '%1'").arg(s.name.c_str()); + 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); QMessageBox::warning(nullptr, tr("Failed to save signal"), text); return false; } @@ -212,8 +229,8 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) { Signal sig = {.is_little_endian = little_endian, .factor = 1}; for (int i = 1; /**/; ++i) { - sig.name = "NEW_SIGNAL_" + std::to_string(i); - if (msg->sigs.count(sig.name.c_str()) == 0) break; + sig.name = QString("NEW_SIGNAL_%1").arg(i); + if (msg->sig(sig.name) == nullptr) break; } updateSigSizeParamsFromRange(sig, start_bit, size); UndoStack::push(new AddSigCommand(msg_id, sig)); @@ -266,8 +283,8 @@ void SignalModel::handleSignalRemoved(const Signal *sig) { SignalItemDelegate::SignalItemDelegate(QObject *parent) { name_validator = new NameValidator(this); double_validator = new QDoubleValidator(this); - small_font.setPointSize(8); double_validator->setLocale(QLocale::C); // Match locale of QString::toDouble() instead of system + small_font.setPointSize(8); } void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -304,7 +321,8 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto item = (SignalModel::Item *)index.internalPointer(); - if (item->type == SignalModel::Item::Name || item->type == SignalModel::Item::Offset || item->type == SignalModel::Item::Factor) { + if (item->type == SignalModel::Item::Name || item->type == SignalModel::Item::Offset || + item->type == SignalModel::Item::Factor || item->type == SignalModel::Item::Min || item->type == SignalModel::Item::Max) { QLineEdit *e = new QLineEdit(parent); e->setFrame(false); e->setValidator(index.row() == 0 ? name_validator : double_validator); @@ -314,6 +332,13 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie spin->setFrame(false); spin->setRange(1, 64); return spin; + } else if (item->type == SignalModel::Item::Desc) { + ValueDescriptionDlg dlg(item->sig->val_desc, parent); + dlg.setWindowTitle(item->sig->name); + if (dlg.exec()) { + ((QAbstractItemModel *)index.model())->setData(index, QVariant::fromValue(dlg.val_desc)); + } + return nullptr; } return QStyledItemDelegate::createEditor(parent, option, index); } @@ -437,7 +462,7 @@ void SignalView::expandSignal(const Signal *sig) { void SignalView::updateChartState() { int i = 0; for (auto item : model->root->children) { - auto plot_btn = tree->indexWidget(model->index(i, 1))->findChildren()[0]; + auto plot_btn = tree->indexWidget(model->index(i, 1))->findChildren()[0]; bool chart_opened = charts->hasSignal(msg_id, item->sig); plot_btn->setChecked(chart_opened); plot_btn->setToolTip(chart_opened ? tr("Close Plot") : tr("Show Plot\nSHIFT click to add to previous opened plot")); @@ -459,3 +484,70 @@ void SignalView::leaveEvent(QEvent *event) { emit highlight(nullptr); QWidget::leaveEvent(event); } + +// ValueDescriptionDlg + +ValueDescriptionDlg::ValueDescriptionDlg(const ValueDescription &descriptions, QWidget *parent) : QDialog(parent) { + QHBoxLayout *toolbar_layout = new QHBoxLayout(); + QPushButton *add = new QPushButton(utils::icon("plus"), ""); + QPushButton *remove = new QPushButton(utils::icon("dash"), ""); + remove->setEnabled(false); + toolbar_layout->addWidget(add); + toolbar_layout->addWidget(remove); + toolbar_layout->addStretch(0); + + table = new QTableWidget(descriptions.size(), 2, this); + table->setItemDelegate(new Delegate(this)); + table->setHorizontalHeaderLabels({"Value", "Description"}); + table->horizontalHeader()->setStretchLastSection(true); + table->setSelectionBehavior(QAbstractItemView::SelectRows); + table->setSelectionMode(QAbstractItemView::SingleSelection); + table->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); + table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + int row = 0; + for (auto &[val, desc] : descriptions) { + table->setItem(row, 0, new QTableWidgetItem(val)); + table->setItem(row, 1, new QTableWidgetItem(desc)); + ++row; + } + + auto btn_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->addLayout(toolbar_layout); + main_layout->addWidget(table); + main_layout->addWidget(btn_box); + setMinimumWidth(500); + + QObject::connect(btn_box, &QDialogButtonBox::accepted, this, &ValueDescriptionDlg::save); + QObject::connect(btn_box, &QDialogButtonBox::rejected, this, &QDialog::reject); + QObject::connect(add, &QPushButton::clicked, [this]() { + table->setRowCount(table->rowCount() + 1); + table->setItem(table->rowCount() - 1, 0, new QTableWidgetItem); + table->setItem(table->rowCount() - 1, 1, new QTableWidgetItem); + }); + QObject::connect(remove, &QPushButton::clicked, [this]() { table->removeRow(table->currentRow()); }); + QObject::connect(table, &QTableWidget::itemSelectionChanged, [=]() { + remove->setEnabled(table->currentRow() != -1); + }); +} + +void ValueDescriptionDlg::save() { + for (int i = 0; i < table->rowCount(); ++i) { + QString val = table->item(i, 0)->text().trimmed(); + QString desc = table->item(i, 1)->text().trimmed(); + if (!val.isEmpty() && !desc.isEmpty()) { + val_desc.push_back({val, desc}); + } + } + QDialog::accept(); +} + +QWidget *ValueDescriptionDlg::Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { + QLineEdit *edit = new QLineEdit(parent); + edit->setFrame(false); + if (index.column() == 0) { + edit->setValidator(new QIntValidator(edit)); + } + return edit; +} diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 7e5015f707..efdc653584 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -4,11 +4,10 @@ #include #include #include +#include #include #include "tools/cabana/chartswidget.h" -#include "tools/cabana/dbcmanager.h" -#include "tools/cabana/streams/abstractstream.h" class SignalModel : public QAbstractItemModel { Q_OBJECT @@ -62,6 +61,21 @@ private: friend class SignalView; }; +class ValueDescriptionDlg : public QDialog { +public: + ValueDescriptionDlg(const ValueDescription &descriptions, QWidget *parent); + ValueDescription val_desc; + +private: + struct Delegate : public QStyledItemDelegate { + Delegate(QWidget *parent) : QStyledItemDelegate(parent) {} + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + }; + + void save(); + QTableWidget *table; +}; + class SignalItemDelegate : public QStyledItemDelegate { public: SignalItemDelegate(QObject *parent); diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index b768b94327..ebd969be61 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -1,7 +1,5 @@ #include "tools/cabana/streams/replaystream.h" -#include "tools/cabana/dbcmanager.h" - ReplayStream::ReplayStream(uint32_t replay_flags, QObject *parent) : replay_flags(replay_flags), AbstractStream(parent, false) { QObject::connect(&settings, &Settings::changed, [this]() { if (replay) replay->setSegmentCacheLimit(settings.max_cached_minutes); diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 69fb738ab8..3505f6abf4 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -1,6 +1,5 @@ #pragma once -#include "opendbc/can/common_dbc.h" #include "tools/cabana/streams/abstractstream.h" #include "tools/cabana/settings.h" diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index 586422ffc8..9a8ab710bc 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -2,8 +2,10 @@ #include "opendbc/can/common.h" #undef INFO #include "catch2/catch.hpp" -#include "tools/cabana/dbcmanager.h" #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"; @@ -18,12 +20,13 @@ TEST_CASE("DBCManager::generateDBC") { auto &new_msgs = dbc_from_generated.messages(); REQUIRE(msgs.size() == new_msgs.size()); for (auto &[address, m] : msgs) { - auto new_m = new_msgs.at(address); + auto &new_m = new_msgs.at(address); REQUIRE(m.name == new_m.name); REQUIRE(m.size == new_m.size); REQUIRE(m.sigs.size() == new_m.sigs.size()); - for (auto &[name, sig] : m.sigs) - REQUIRE(sig == new_m.sigs[name]); + for (int i = 0; i < m.sigs.size(); ++i) { + REQUIRE(m.sigs[i] == new_m.sigs[i]); + } } } @@ -37,13 +40,13 @@ TEST_CASE("Parse can messages") { REQUIRE(log.events.size() > 0); for (auto e : log.events) { if (e->which == cereal::Event::Which::CAN) { - std::map, std::vector> values_1; + std::map, std::vector> values_1; for (const auto &c : e->event.getCan()) { const auto msg = dbc.msg(c.getAddress()); if (c.getSrc() == 0 && msg) { - for (auto &[name, sig] : msg->sigs) { + for (auto &sig : msg->sigs) { double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), sig); - values_1[{c.getAddress(), name.toStdString()}].push_back(val); + values_1[{c.getAddress(), sig.name}].push_back(val); } } } @@ -53,7 +56,7 @@ TEST_CASE("Parse can messages") { for (auto &[key, v1] : values_1) { bool found = false; for (auto &v2 : values_2) { - if (v2.address == key.first && v2.name == key.second) { + if (v2.address == key.first && key.second == v2.name.c_str()) { REQUIRE(v2.all_values.size() == v1.size()); REQUIRE(v2.all_values == v1); found = true; diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index ffb0e54b0e..27cb7bced8 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -9,6 +9,7 @@ #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")); diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index 53d7806a8f..ba9b063baf 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -7,6 +7,7 @@ #include #include "tools/cabana/dbcmanager.h" +using namespace dbcmanager; class FindSimilarBitsDlg : public QDialog { Q_OBJECT diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 9843a3f00c..6415cc8e16 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -106,7 +106,7 @@ QColor getColor(const Signal *sig) { float h = 19 * (float)sig->lsb / 64.0; h = fmod(h, 1.0); - size_t hash = qHash(QString::fromStdString(sig->name)); + size_t hash = qHash(sig->name); float s = 0.25 + 0.25 * (float)(hash & 0xff) / 255.0; float v = 0.75 + 0.25 * (float)((hash >> 8) & 0xff) / 255.0; diff --git a/tools/cabana/util.h b/tools/cabana/util.h index eb5203fb0b..2717451061 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -9,7 +9,9 @@ #include #include -#include "opendbc/can/common_dbc.h" +#include "tools/cabana/dbcmanager.h" +using namespace dbcmanager; + class ChangeTracker { public: @@ -37,7 +39,7 @@ public: inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } inline char toHex(uint value) { return "0123456789ABCDEF"[value & 0xF]; } -QColor getColor(const Signal *sig); +QColor getColor(const dbcmanager::Signal *sig); class NameValidator : public QRegExpValidator { Q_OBJECT diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 51197eedd6..1a7e27f1b3 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -11,7 +11,9 @@ #include "selfdrive/ui/qt/widgets/cameraview.h" #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