cabana: refactor dbc manager (#28445)

* rafactor signal

* cleanup

* refacto dbcmanager

* refactor dbcmanger
old-commit-hash: ff4aae85fe
beeps
Dean Lee 2 years ago committed by GitHub
parent 97e62cf6c5
commit eba8100ea5
  1. 9
      tools/cabana/binaryview.cc
  2. 12
      tools/cabana/chart/chart.cc
  3. 2
      tools/cabana/chart/chart.h
  4. 2
      tools/cabana/chart/signalselector.cc
  5. 2
      tools/cabana/chart/sparkline.cc
  6. 113
      tools/cabana/dbc/dbc.cc
  7. 88
      tools/cabana/dbc/dbc.h
  8. 118
      tools/cabana/dbc/dbcfile.cc
  9. 33
      tools/cabana/dbc/dbcfile.h
  10. 295
      tools/cabana/dbc/dbcmanager.cc
  11. 77
      tools/cabana/dbc/dbcmanager.h
  12. 2
      tools/cabana/historylog.cc
  13. 2
      tools/cabana/historylog.h
  14. 58
      tools/cabana/mainwin.cc
  15. 1
      tools/cabana/mainwin.h
  16. 2
      tools/cabana/messageswidget.cc
  17. 10
      tools/cabana/signalview.cc
  18. 28
      tools/cabana/tests/test_cabana.cc
  19. 6
      tools/cabana/tools/findsimilarbits.cc
  20. 20
      tools/cabana/util.cc
  21. 5
      tools/cabana/util.h

@ -165,7 +165,7 @@ void BinaryView::mousePressEvent(QMouseEvent *event) {
if (bit_idx == s->lsb || bit_idx == s->msb) {
anchor_index = model->bitIndex(bit_idx == s->lsb ? s->msb : s->lsb, true);
resize_sig = s;
delegate->selection_color = getColor(s);
delegate->selection_color = s->color;
break;
}
}
@ -381,7 +381,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
if (item->sigs.size() > 0) {
for (auto &s : item->sigs) {
if (s == bin_view->hovered_sig) {
painter->fillRect(option.rect, getColor(bin_view->hovered_sig).darker(125)); // 4/5x brightness
painter->fillRect(option.rect, s->color.darker(125)); // 4/5x brightness
} else {
drawSignalCell(painter, option, index, s);
}
@ -434,15 +434,14 @@ void BinaryItemDelegate::drawSignalCell(QPainter *painter, const QStyleOptionVie
painter->setClipRegion(QRegion(rc).subtracted(subtract));
auto item = (const BinaryViewModel::Item *)index.internalPointer();
auto sig_color = getColor(sig);
QColor color = sig_color;
QColor color = sig->color;
color.setAlpha(item->bg_color.alpha());
// Mixing the signal colour with the Base background color to fade it
painter->fillRect(rc, QApplication::palette().color(QPalette::Base));
painter->fillRect(rc, color);
// Draw edges
color = sig_color.darker(125);
color = sig->color.darker(125);
painter->setPen(QPen(color, 1));
if (draw_left) painter->drawLine(rc.topLeft(), rc.bottomLeft());
if (draw_right) painter->drawLine(rc.topRight(), rc.bottomRight());

@ -38,7 +38,6 @@ ChartView::ChartView(const std::pair<double, double> &x_range, ChartsWidget *par
setChart(chart);
createToolButtons();
// TODO: enable zoomIn/seekTo in live streaming mode.
setRubberBand(QChartView::HorizontalRubberBand);
setMouseTracking(true);
setTheme(settings.theme == DARK_THEME ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight);
@ -107,14 +106,14 @@ void ChartView::setTheme(QChart::ChartTheme theme) {
chart()->legend()->setLabelColor(palette().color(QPalette::Text));
}
for (auto &s : sigs) {
s.series->setColor(getColor(s.sig));
s.series->setColor(s.sig->color);
}
}
void ChartView::addSignal(const MessageId &msg_id, const cabana::Signal *sig) {
if (hasSignal(msg_id, sig)) return;
QXYSeries *series = createSeries(series_type, getColor(sig));
QXYSeries *series = createSeries(series_type, sig->color);
sigs.push_back({.msg_id = msg_id, .sig = sig, .series = series});
updateSeries(sig);
updateSeriesPoints();
@ -154,8 +153,9 @@ void ChartView::signalUpdated(const cabana::Signal *sig) {
}
void ChartView::msgUpdated(MessageId id) {
if (std::any_of(sigs.cbegin(), sigs.cend(), [=](auto &s) { return s.msg_id == id; }))
if (std::any_of(sigs.cbegin(), sigs.cend(), [=](auto &s) { return s.msg_id.address == id.address; })) {
updateTitle();
}
}
void ChartView::manageSignals() {
@ -277,7 +277,7 @@ void ChartView::updateSeries(const cabana::Signal *sig, bool clear) {
s.step_vals.clear();
s.last_value_mono_time = 0;
}
s.series->setColor(getColor(s.sig));
s.series->setColor(s.sig->color);
const auto &msgs = can->events(s.msg_id);
s.vals.reserve(msgs.capacity());
@ -799,7 +799,7 @@ void ChartView::setSeriesType(SeriesType type) {
s.series->deleteLater();
}
for (auto &s : sigs) {
auto series = createSeries(series_type, getColor(s.sig));
auto series = createSeries(series_type, s.sig->color);
series->replace(series_type == SeriesType::StepLine ? s.step_vals : s.vals);
s.series = series;
}

@ -56,7 +56,7 @@ private slots:
void manageSignals();
void handleMarkerClicked();
void msgUpdated(MessageId id);
void msgRemoved(MessageId id) { removeIf([=](auto &s) { return s.msg_id == id; }); }
void msgRemoved(MessageId id) { removeIf([=](auto &s) { return s.msg_id.address == id.address && !dbc()->msg(id); }); }
void signalRemoved(const cabana::Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); }
private:

@ -91,7 +91,7 @@ void SignalSelector::updateAvailableList(int index) {
}
void SignalSelector::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);
QString text = QString("<span style=\"color:%0;\">■ </span> %1").arg(sig->color.name(), sig->name);
if (show_msg_name) text += QString(" <font color=\"gray\">%0 %1</font>").arg(msgName(id), id.toString());
QLabel *label = new QLabel(text);

@ -37,7 +37,7 @@ void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, doubl
max_val += 1;
}
}
render(getColor(sig), size);
render(sig->color, size);
} else {
pixmap = QPixmap();
min_val = -1;

@ -1,32 +1,96 @@
#include "tools/cabana/dbc/dbc.h"
#include "tools/cabana/util.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) {
if (l->start_bit != r->start_bit) {
return l->start_bit < r->start_bit;
}
// For VECTOR__INDEPENDENT_SIG_MSG, many signals have same start bit
return l->name < r->name;
});
return ret;
// cabana::Msg
cabana::Msg::~Msg() {
for (auto s : sigs) {
delete s;
}
}
cabana::Signal *cabana::Msg::addSignal(const cabana::Signal &sig) {
auto s = sigs.emplace_back(new cabana::Signal(sig));
update();
return s;
}
cabana::Signal *cabana::Msg::updateSignal(const QString &sig_name, const cabana::Signal &new_sig) {
auto s = sig(sig_name);
if (s) {
*s = new_sig;
update();
}
return s;
}
void cabana::Msg::removeSignal(const QString &sig_name) {
auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s->name == sig_name; });
if (it != sigs.end()) {
delete *it;
sigs.erase(it);
update();
}
}
cabana::Msg &cabana::Msg::operator=(const cabana::Msg &other) {
address = other.address;
name = other.name;
size = other.size;
comment = other.comment;
for (auto s : sigs) delete s;
sigs.clear();
for (auto s : other.sigs) {
sigs.push_back(new cabana::Signal(*s));
}
update();
return *this;
}
cabana::Signal *cabana::Msg::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;
}
int cabana::Msg::indexOf(const cabana::Signal *sig) const {
for (int i = 0; i < sigs.size(); ++i) {
if (sigs[i] == sig) return i;
}
return -1;
}
void cabana::Msg::updateMask() {
QString cabana::Msg::newSignalName() {
QString new_name;
for (int i = 1; /**/; ++i) {
new_name = QString("NEW_SIGNAL_%1").arg(i);
if (sig(new_name) == nullptr) break;
}
return new_name;
}
void cabana::Msg::update() {
mask = QVector<uint8_t>(size, 0x00).toList();
// sort signals
std::sort(sigs.begin(), sigs.end(), [](auto l, auto r) {
return std::tie(l->start_bit, l->name) < std::tie(r->start_bit, r->name);
});
for (auto &sig : sigs) {
int i = sig.msb / 8;
int bits = sig.size;
sig->update();
// update mask
int i = sig->msb / 8;
int bits = sig->size;
while (i >= 0 && i < 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 lsb = (int)(sig->lsb / 8) == i ? sig->lsb : i * 8;
int msb = (int)(sig->msb / 8) == i ? sig->msb : (i + 1) * 8 - 1;
int sz = msb - lsb + 1;
int shift = (lsb - (i * 8));
@ -34,18 +98,27 @@ void cabana::Msg::updateMask() {
mask[i] |= ((1ULL << sz) - 1) << shift;
bits -= size;
i = sig.is_little_endian ? i - 1 : i + 1;
i = sig->is_little_endian ? i - 1 : i + 1;
}
}
}
void cabana::Signal::updatePrecision() {
// cabana::Signal
void cabana::Signal::update() {
float h = 19 * (float)lsb / 64.0;
h = fmod(h, 1.0);
size_t hash = qHash(name);
float s = 0.25 + 0.25 * (float)(hash & 0xff) / 255.0;
float v = 0.75 + 0.25 * (float)((hash >> 8) & 0xff) / 255.0;
color = QColor::fromHsvF(h, s, v);
precision = std::max(num_decimals(factor), num_decimals(offset));
}
QString cabana::Signal::formatValue(double value) const {
// Show enum string
for (auto &[val, desc] : val_desc) {
for (const auto &[val, desc] : val_desc) {
if (std::abs(value - val) < 1e-6) {
return desc;
}

@ -1,9 +1,10 @@
#pragma once
#include <limits>
#include <QColor>
#include <QList>
#include <QMetaType>
#include <QString>
#include <limits>
#include "opendbc/can/common_dbc.h"
@ -45,41 +46,55 @@ struct std::hash<MessageId> {
typedef QList<std::pair<double, QString>> ValueDescription;
namespace cabana {
struct Signal {
QString name;
int start_bit, msb, lsb, size;
bool is_signed;
double factor, offset;
bool is_little_endian;
double min, max;
QString unit;
QString comment;
ValueDescription val_desc;
int precision = 0;
void updatePrecision();
QString formatValue(double value) const;
};
struct Msg {
uint32_t address;
QString name;
uint32_t size;
QString comment;
QList<cabana::Signal> sigs;
QList<uint8_t> mask;
void updateMask();
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); }
}
class Signal {
public:
Signal() = default;
Signal(const Signal &other) = default;
void update();
QString formatValue(double value) const;
QString name;
int start_bit, msb, lsb, size;
double factor, offset;
bool is_signed;
bool is_little_endian;
double min, max;
QString unit;
QString comment;
ValueDescription val_desc;
int precision = 0;
QColor color;
};
class Msg {
public:
Msg() = default;
Msg(const Msg &other) { *this = other; }
~Msg();
cabana::Signal *addSignal(const cabana::Signal &sig);
cabana::Signal *updateSignal(const QString &sig_name, const cabana::Signal &sig);
void removeSignal(const QString &sig_name);
Msg &operator=(const Msg &other);
int indexOf(const cabana::Signal *sig) const;
cabana::Signal *sig(const QString &sig_name) const;
QString newSignalName();
inline const std::vector<cabana::Signal *> &getSignals() const { return sigs; }
uint32_t address;
QString name;
uint32_t size;
QString comment;
std::vector<cabana::Signal *> sigs;
QList<uint8_t> mask;
void update();
};
bool operator==(const cabana::Signal &l, const cabana::Signal &r);
inline bool operator!=(const cabana::Signal &l, const cabana::Signal &r) { return !(l == r); }
} // namespace cabana
// Helper functions
double get_raw_value(const uint8_t *data, size_t data_size, const cabana::Signal &sig);
@ -89,4 +104,3 @@ void updateSigSizeParamsFromRange(cabana::Signal &s, int start_bit, int size);
std::pair<int, int> getSignalRange(const cabana::Signal *s);
inline std::vector<std::string> allDBCNames() { return get_dbc_names(); }
inline QString doubleToString(double value) { return QString::number(value, 'g', std::numeric_limits<double>::digits10); }

@ -37,20 +37,18 @@ void DBCFile::open(const QString &content) {
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;
sig.updatePrecision();
auto sig = m.sigs.emplace_back(new cabana::Signal);
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;
}
m.updateMask();
m.update();
}
parseExtraInfo(content);
@ -58,7 +56,7 @@ void DBCFile::open(const QString &content) {
}
bool DBCFile::save() {
assert (!filename.isEmpty());
assert(!filename.isEmpty());
if (writeContents(filename)) {
cleanupAutoSaveFile();
return true;
@ -90,41 +88,6 @@ bool DBCFile::writeContents(const QString &fn) {
return false;
}
cabana::Signal *DBCFile::addSignal(const MessageId &id, const cabana::Signal &sig) {
if (auto m = const_cast<cabana::Msg *>(msg(id.address))) {
m->sigs.push_back(sig);
m->updateMask();
return &m->sigs.last();
}
return nullptr;
}
cabana::Signal *DBCFile::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;
m->updateMask();
return s;
}
}
return nullptr;
}
cabana::Signal *DBCFile::getSignal(const MessageId &id, const QString &sig_name) {
auto m = msg(id);
return m ? (cabana::Signal *)m->sig(sig_name) : nullptr;
}
void DBCFile::removeSignal(const MessageId &id, const QString &sig_name) {
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()) {
m->sigs.erase(it);
m->updateMask();
}
}
}
void DBCFile::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment) {
auto &m = msgs[id.address];
m.address = id.address;
@ -133,60 +96,17 @@ void DBCFile::updateMsg(const MessageId &id, const QString &name, uint32_t size,
m.comment = comment;
}
void DBCFile::removeMsg(const MessageId &id) {
msgs.erase(id.address);
}
QString DBCFile::newMsgName(const MessageId &id) {
return QString("NEW_MSG_") + QString::number(id.address, 16).toUpper();
}
QString DBCFile::newSignalName(const MessageId &id) {
auto m = msg(id);
assert(m != nullptr);
QString name;
for (int i = 1; /**/; ++i) {
name = QString("NEW_SIGNAL_%1").arg(i);
if (m->sig(name) == nullptr) break;
}
return name;
}
const QList<uint8_t>& DBCFile::mask(const MessageId &id) const {
auto m = msg(id);
return m ? m->mask : empty_mask;
}
const cabana::Msg *DBCFile::msg(uint32_t address) const {
cabana::Msg *DBCFile::msg(uint32_t address) {
auto it = msgs.find(address);
return it != msgs.end() ? &it->second : nullptr;
}
const cabana::Msg* DBCFile::msg(const QString &name) {
auto it = std::find_if(msgs.cbegin(), msgs.cend(), [&name](auto &m) { return m.second.name == name; });
return it != msgs.cend() ? &(it->second) : nullptr;
}
QStringList DBCFile::signalNames() const {
// Used for autocompletion
QStringList ret;
for (auto const& [_, msg] : msgs) {
for (auto sig: msg.getSignals()) {
ret << sig->name;
}
}
ret.sort();
ret.removeDuplicates();
return ret;
}
int DBCFile::signalCount(const MessageId &id) const {
if (msgs.count(id.address) == 0) return 0;
return msgs.at(id.address).sigs.size();
cabana::Msg *DBCFile::msg(const QString &name) {
auto it = std::find_if(msgs.begin(), msgs.end(), [&name](auto &m) { return m.second.name == name; });
return it != msgs.end() ? &(it->second) : nullptr;
}
int DBCFile::signalCount() const {
int DBCFile::signalCount() {
return std::accumulate(msgs.cbegin(), msgs.cend(), 0, [](int &n, const auto &m) { return n + m.second.sigs.size(); });
}
@ -194,8 +114,8 @@ void DBCFile::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 msg_comment_regexp(R"(^CM_ BO_ *(\w+) *\"([^"]*)\";)");
static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"([^"]*)\";)");
static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(\w+) *\"([^"]*)\"\s*;)");
static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"([^"]*)\"\s*;)");
static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (\s*[-+]?[0-9]+\s+\".+?\"[^;]*))");
int line_num = 0;

@ -1,9 +1,7 @@
#pragma once
#include <map>
#include <QList>
#include <QObject>
#include <QString>
#include "tools/cabana/dbc/dbc.h"
@ -26,30 +24,18 @@ public:
void cleanupAutoSaveFile();
QString generateDBC();
cabana::Signal *addSignal(const MessageId &id, const cabana::Signal &sig);
cabana::Signal *updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig);
cabana::Signal *getSignal(const MessageId &id, const QString &sig_name);
void removeSignal(const MessageId &id, const QString &sig_name);
void updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment);
void removeMsg(const MessageId &id);
QString newMsgName(const MessageId &id);
QString newSignalName(const MessageId &id);
const QList<uint8_t>& mask(const MessageId &id) const;
inline void removeMsg(const MessageId &id) { msgs.erase(id.address); }
inline std::map<uint32_t, cabana::Msg> getMessages() const { return msgs; }
const cabana::Msg *msg(uint32_t address) const;
const cabana::Msg* msg(const QString &name);
inline const cabana::Msg *msg(const MessageId &id) const { return msg(id.address); };
inline const std::map<uint32_t, cabana::Msg> &getMessages() const { return msgs; }
cabana::Msg *msg(uint32_t address);
cabana::Msg *msg(const QString &name);
inline cabana::Msg *msg(const MessageId &id) { return msg(id.address); }
QStringList signalNames() const;
int signalCount(const MessageId &id) const;
int signalCount() const;
inline int msgCount() const { return msgs.size(); }
inline QString name() const { return name_.isEmpty() ? "untitled" : name_; }
inline bool isEmpty() const { return (signalCount() == 0) && name_.isEmpty(); }
int signalCount();
inline int msgCount() { return msgs.size(); }
inline QString name() { return name_.isEmpty() ? "untitled" : name_; }
inline bool isEmpty() { return (signalCount() == 0) && name_.isEmpty(); }
QString filename;
@ -57,5 +43,4 @@ private:
void parseExtraInfo(const QString &content);
std::map<uint32_t, cabana::Msg> msgs;
QString name_;
QList<uint8_t> empty_mask;
};

@ -1,21 +1,16 @@
#include "tools/cabana/dbc/dbcmanager.h"
#include <algorithm>
bool DBCManager::open(SourceSet s, const QString &dbc_file_name, QString *error) {
for (int i = 0; i < dbc_files.size(); i++) {
auto [ss, dbc_file] = dbc_files[i];
// Check if file is already open, and merge sources
if (dbc_file->filename == dbc_file_name) {
dbc_files[i] = {ss | s, dbc_file};
emit DBCFileChanged();
return true;
}
}
#include <algorithm>
#include <numeric>
bool DBCManager::open(const SourceSet &sources, const QString &dbc_file_name, QString *error) {
try {
dbc_files.push_back({s, new DBCFile(dbc_file_name, this)});
auto it = std::find_if(dbc_files.begin(), dbc_files.end(),
[&](auto &f) { return f.second && f.second->filename == dbc_file_name; });
auto file = (it != dbc_files.end()) ? it->second : std::make_shared<DBCFile>(dbc_file_name, this);
for (auto s : sources) {
dbc_files[s] = file;
}
} catch (std::exception &e) {
if (error) *error = e.what();
return false;
@ -25,9 +20,12 @@ bool DBCManager::open(SourceSet s, const QString &dbc_file_name, QString *error)
return true;
}
bool DBCManager::open(SourceSet s, const QString &name, const QString &content, QString *error) {
bool DBCManager::open(const SourceSet &sources, const QString &name, const QString &content, QString *error) {
try {
dbc_files.push_back({s, new DBCFile(name, content, this)});
auto file = std::make_shared<DBCFile>(name, content, this);
for (auto s : sources) {
dbc_files[s] = file;
}
} catch (std::exception &e) {
if (error) *error = e.what();
return false;
@ -37,263 +35,154 @@ bool DBCManager::open(SourceSet s, const QString &name, const QString &content,
return true;
}
void DBCManager::close(SourceSet s) {
// Build new list of dbc files, removing the ones that match the sourceset
QList<std::pair<SourceSet, DBCFile*>> new_dbc_files;
for (auto entry : dbc_files) {
if (entry.first == s) {
delete entry.second;
} else {
new_dbc_files.push_back(entry);
}
void DBCManager::close(const SourceSet &sources) {
for (auto s : sources) {
dbc_files[s] = nullptr;
}
dbc_files = new_dbc_files;
emit DBCFileChanged();
}
void DBCManager::close(DBCFile *dbc_file) {
assert(dbc_file != nullptr);
// Build new list of dbc files, removing the one that matches dbc_file*
QList<std::pair<SourceSet, DBCFile*>> new_dbc_files;
for (auto entry : dbc_files) {
if (entry.second == dbc_file) {
delete entry.second;
} else {
new_dbc_files.push_back(entry);
}
for (auto &[_, f] : dbc_files) {
if (f.get() == dbc_file) f = nullptr;
}
dbc_files = new_dbc_files;
emit DBCFileChanged();
}
void DBCManager::closeAll() {
if (dbc_files.isEmpty()) return;
while (dbc_files.size()) {
DBCFile *dbc_file = dbc_files.back().second;
dbc_files.pop_back();
delete dbc_file;
}
dbc_files.clear();
emit DBCFileChanged();
}
void DBCManager::removeSourcesFromFile(DBCFile *dbc_file, SourceSet s) {
assert(dbc_file != nullptr);
// Build new list of dbc files, for the given dbc_file* remove s from the current sources
QList<std::pair<SourceSet, DBCFile*>> new_dbc_files;
for (auto entry : dbc_files) {
if (entry.second == dbc_file) {
SourceSet ss = (entry.first == SOURCE_ALL) ? sources : entry.first;
ss -= s;
if (ss.empty()) { // Close file if no more sources remain
delete dbc_file;
} else {
new_dbc_files.push_back({ss, dbc_file});
}
} else {
new_dbc_files.push_back(entry);
}
}
dbc_files = new_dbc_files;
emit DBCFileChanged();
}
void DBCManager::addSignal(const MessageId &id, const cabana::Signal &sig) {
auto sources_dbc_file = findDBCFile(id);
assert(sources_dbc_file); // Create new DBC?
auto [dbc_sources, dbc_file] = *sources_dbc_file;
cabana::Signal *s = dbc_file->addSignal(id, sig);
if (s != nullptr) {
dbc_sources.insert(id.source);
for (uint8_t source : dbc_sources) {
emit signalAdded({.source = source, .address = id.address}, s);
if (auto m = msg(id)) {
if (auto s = m->addSignal(sig)) {
emit signalAdded(id, s);
}
}
}
void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig) {
auto sources_dbc_file = findDBCFile(id);
assert(sources_dbc_file); // This should be impossible
auto [_, dbc_file] = *sources_dbc_file;
cabana::Signal *s = dbc_file->updateSignal(id, sig_name, sig);
if (s != nullptr) {
emit signalUpdated(s);
if (auto m = msg(id)) {
if (auto s = m->updateSignal(sig_name, sig)) {
emit signalUpdated(s);
}
}
}
void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) {
auto sources_dbc_file = findDBCFile(id);
assert(sources_dbc_file); // This should be impossible
auto [_, dbc_file] = *sources_dbc_file;
cabana::Signal *s = dbc_file->getSignal(id, sig_name);
if (s != nullptr) {
emit signalRemoved(s);
dbc_file->removeSignal(id, sig_name);
if (auto m = msg(id)) {
if (auto s = m->sig(sig_name)) {
emit signalRemoved(s);
m->removeSignal(sig_name);
}
}
}
void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment) {
auto sources_dbc_file = findDBCFile(id);
assert(sources_dbc_file); // This should be impossible
auto [dbc_sources, dbc_file] = *sources_dbc_file;
auto dbc_file = findDBCFile(id);
assert(dbc_file); // This should be impossible
dbc_file->updateMsg(id, name, size, comment);
for (uint8_t source : dbc_sources) {
emit msgUpdated({.source = source, .address = id.address});
}
emit msgUpdated(id);
}
void DBCManager::removeMsg(const MessageId &id) {
auto sources_dbc_file = findDBCFile(id);
assert(sources_dbc_file); // This should be impossible
auto [dbc_sources, dbc_file] = *sources_dbc_file;
auto dbc_file = findDBCFile(id);
assert(dbc_file); // This should be impossible
dbc_file->removeMsg(id);
for (uint8_t source : dbc_sources) {
emit msgRemoved({.source = source, .address = id.address});
}
emit msgRemoved(id);
}
QString DBCManager::newMsgName(const MessageId &id) {
auto sources_dbc_file = findDBCFile(id);
assert(sources_dbc_file); // This should be impossible
auto [_, dbc_file] = *sources_dbc_file;
return dbc_file->newMsgName(id);
return QString("NEW_MSG_") + QString::number(id.address, 16).toUpper();
}
QString DBCManager::newSignalName(const MessageId &id) {
auto sources_dbc_file = findDBCFile(id);
assert(sources_dbc_file); // This should be impossible
auto [_, dbc_file] = *sources_dbc_file;
return dbc_file->newSignalName(id);
auto m = msg(id);
return m ? m->newSignalName() : "";
}
const QList<uint8_t>& DBCManager::mask(const MessageId &id) const {
auto sources_dbc_file = findDBCFile(id);
if (!sources_dbc_file) {
return empty_mask;
}
auto [_, dbc_file] = *sources_dbc_file;
return dbc_file->mask(id);
const QList<uint8_t> &DBCManager::mask(const MessageId &id) {
static QList<uint8_t> empty_mask;
auto m = msg(id);
return m ? m->mask : empty_mask;
}
std::map<MessageId, cabana::Msg> DBCManager::getMessages(uint8_t source) {
std::map<MessageId, cabana::Msg> ret;
auto sources_dbc_file = findDBCFile({.source = source, .address = 0});
if (!sources_dbc_file) {
return ret;
}
auto [_, dbc_file] = *sources_dbc_file;
for (auto &[address, msg] : dbc_file->getMessages()) {
MessageId id = {.source = source, .address = address};
ret[id] = msg;
}
return ret;
const std::map<uint32_t, cabana::Msg> &DBCManager::getMessages(uint8_t source) {
static std::map<uint32_t, cabana::Msg> empty_msgs;
auto dbc_file = findDBCFile(source);
return dbc_file ? dbc_file->getMessages() : empty_msgs;
}
const cabana::Msg *DBCManager::msg(const MessageId &id) const {
auto sources_dbc_file = findDBCFile(id);
if (!sources_dbc_file) {
return nullptr;
}
auto [_, dbc_file] = *sources_dbc_file;
return dbc_file->msg(id);
cabana::Msg *DBCManager::msg(const MessageId &id) {
auto dbc_file = findDBCFile(id);
return dbc_file ? dbc_file->msg(id) : nullptr;
}
const cabana::Msg* DBCManager::msg(uint8_t source, const QString &name) {
auto sources_dbc_file = findDBCFile({.source = source, .address = 0});
if (!sources_dbc_file) {
return nullptr;
}
auto [_, dbc_file] = *sources_dbc_file;
return dbc_file->msg(name);
cabana::Msg *DBCManager::msg(uint8_t source, const QString &name) {
auto dbc_file = findDBCFile(source);
return dbc_file ? dbc_file->msg(name) : nullptr;
}
QStringList DBCManager::signalNames() const {
QStringList DBCManager::signalNames() {
// Used for autocompletion
QStringList ret;
for (auto &[_, dbc_file] : dbc_files) {
ret << dbc_file->signalNames();
for (auto &f : allDBCFiles()) {
for (auto &[_, m] : f->getMessages()) {
for (auto sig : m.getSignals()) {
ret << sig->name;
}
}
}
ret.sort();
ret.removeDuplicates();
return ret;
}
int DBCManager::signalCount(const MessageId &id) const {
auto sources_dbc_file = findDBCFile(id);
if (!sources_dbc_file) {
return 0;
}
auto [_, dbc_file] = *sources_dbc_file;
return dbc_file->signalCount(id);
}
int DBCManager::signalCount() const {
int ret = 0;
for (auto &[_, dbc_file] : dbc_files) {
ret += dbc_file->signalCount();
}
return ret;
int DBCManager::signalCount(const MessageId &id) {
auto m = msg(id);
return m ? m->sigs.size() : 0;
}
int DBCManager::msgCount() const {
int ret = 0;
for (auto &[_, dbc_file] : dbc_files) {
ret += dbc_file->msgCount();
}
return ret;
int DBCManager::signalCount() {
auto files = allDBCFiles();
return std::accumulate(files.cbegin(), files.cend(), 0, [](int &n, auto &f) { return n + f->signalCount(); });
}
int DBCManager::dbcCount() const {
return dbc_files.size();
int DBCManager::msgCount() {
auto files = allDBCFiles();
return std::accumulate(files.cbegin(), files.cend(), 0, [](int &n, auto &f) { return n + f->msgCount(); });
}
int DBCManager::nonEmptyDBCCount() const {
return std::count_if(dbc_files.cbegin(), dbc_files.cend(), [](auto &f) { return !f.second->isEmpty(); });
int DBCManager::dbcCount() {
return allDBCFiles().size();
}
void DBCManager::updateSources(const SourceSet &s) {
sources = s;
int DBCManager::nonEmptyDBCCount() {
auto files = allDBCFiles();
return std::count_if(files.cbegin(), files.cend(), [](auto &f) { return !f->isEmpty(); });
}
std::optional<std::pair<SourceSet, DBCFile*>> DBCManager::findDBCFile(const uint8_t source) const {
DBCFile *DBCManager::findDBCFile(const uint8_t source) {
// Find DBC file that matches id.source, fall back to SOURCE_ALL if no specific DBC is found
auto it = dbc_files.count(source) ? dbc_files.find(source) : dbc_files.find(-1);
return it != dbc_files.end() ? it->second.get() : nullptr;
}
for (auto &[source_set, dbc_file] : dbc_files) {
if (source_set.contains(source)) return {{source_set, dbc_file}};
std::set<DBCFile *> DBCManager::allDBCFiles() {
std::set<DBCFile *> files;
for (const auto &[_, f] : dbc_files) {
if (f) files.insert(f.get());
}
for (auto &[source_set, dbc_file] : dbc_files) {
if (source_set == SOURCE_ALL) return {{sources, dbc_file}};
}
return {};
return files;
}
std::optional<std::pair<SourceSet, DBCFile*>> DBCManager::findDBCFile(const MessageId &id) const {
return findDBCFile(id.source);
const SourceSet DBCManager::sources(const DBCFile *dbc_file) const {
SourceSet sources;
for (auto &[s, f] : dbc_files) {
if (f.get() == dbc_file) sources.insert(s);
}
return sources;
}
DBCManager *dbc() {

@ -1,20 +1,15 @@
#pragma once
#include <memory>
#include <map>
#include <optional>
#include <set>
#include <QList>
#include <QMetaType>
#include <QObject>
#include <QString>
#include <QSet>
#include "tools/cabana/dbc/dbc.h"
#include "tools/cabana/dbc/dbcfile.h"
typedef QSet<uint8_t> SourceSet;
const SourceSet SOURCE_ALL = {};
typedef std::set<int> SourceSet;
const SourceSet SOURCE_ALL = {-1};
const int INVALID_SOURCE = 0xff;
inline bool operator<(const std::shared_ptr<DBCFile> &l, const std::shared_ptr<DBCFile> &r) { return l.get() < r.get(); }
class DBCManager : public QObject {
Q_OBJECT
@ -22,12 +17,11 @@ class DBCManager : public QObject {
public:
DBCManager(QObject *parent) {}
~DBCManager() {}
bool open(SourceSet s, const QString &dbc_file_name, QString *error = nullptr);
bool open(SourceSet s, const QString &name, const QString &content, QString *error = nullptr);
void close(SourceSet s);
bool open(const SourceSet &sources, const QString &dbc_file_name, QString *error = nullptr);
bool open(const SourceSet &sources, const QString &name, const QString &content, QString *error = nullptr);
void close(const SourceSet &sources);
void close(DBCFile *dbc_file);
void closeAll();
void removeSourcesFromFile(DBCFile *dbc_file, SourceSet s);
void addSignal(const MessageId &id, const cabana::Signal &sig);
void updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig);
@ -38,31 +32,23 @@ public:
QString newMsgName(const MessageId &id);
QString newSignalName(const MessageId &id);
const QList<uint8_t>& mask(const MessageId &id);
const QList<uint8_t>& mask(const MessageId &id) const;
std::map<MessageId, cabana::Msg> getMessages(uint8_t source);
const cabana::Msg *msg(const MessageId &id) const;
const cabana::Msg* msg(uint8_t source, const QString &name);
QStringList signalNames() const;
int signalCount(const MessageId &id) const;
int signalCount() const;
int msgCount() const;
int dbcCount() const;
int nonEmptyDBCCount() const;
std::optional<std::pair<SourceSet, DBCFile*>> findDBCFile(const uint8_t source) const;
std::optional<std::pair<SourceSet, DBCFile*>> findDBCFile(const MessageId &id) const;
const std::map<uint32_t, cabana::Msg> &getMessages(uint8_t source);
cabana::Msg *msg(const MessageId &id);
cabana::Msg* msg(uint8_t source, const QString &name);
QList<std::pair<SourceSet, DBCFile*>> dbc_files;
QStringList signalNames();
int signalCount(const MessageId &id);
int signalCount();
int msgCount();
int dbcCount();
int nonEmptyDBCCount();
private:
SourceSet sources;
QList<uint8_t> empty_mask;
public slots:
void updateSources(const SourceSet &s);
const SourceSet sources(const DBCFile *dbc_file) const;
DBCFile *findDBCFile(const uint8_t source);
inline DBCFile *findDBCFile(const MessageId &id) { return findDBCFile(id.source); }
std::set<DBCFile *> allDBCFiles();
signals:
void signalAdded(MessageId id, const cabana::Signal *sig);
@ -71,6 +57,9 @@ signals:
void msgUpdated(MessageId id);
void msgRemoved(MessageId id);
void DBCFileChanged();
private:
std::map<int, std::shared_ptr<DBCFile>> dbc_files;
};
DBCManager *dbc();
@ -80,16 +69,10 @@ inline QString msgName(const MessageId &id) {
return msg ? msg->name : UNTITLED;
}
inline QString toString(SourceSet ss) {
if (ss == SOURCE_ALL) {
return "all";
} else {
QStringList ret;
QList source_list = ss.values();
std::sort(source_list.begin(), source_list.end());
for (auto s : source_list) {
ret << QString::number(s);
}
return ret.join(", ");
inline QString toString(const SourceSet &ss) {
QStringList ret;
for (auto s : ss) {
ret << (s == -1 ? QString("all") : QString::number(s));
}
return ret.join(", ");
}

@ -64,7 +64,7 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i
}
} else if (role == Qt::BackgroundRole && section > 0 && show_signals) {
// Alpha-blend the signal color with the background to ensure contrast
QColor sigColor = getColor(sigs[section - 1]);
QColor sigColor = sigs[section - 1]->color;
sigColor.setAlpha(128);
return QBrush(sigColor);
}

@ -62,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 cabana::Signal *> sigs;
std::vector<cabana::Signal *> sigs;
bool dynamic_mode = true;
bool display_signals_mode = true;
};

@ -353,7 +353,6 @@ void MainWindow::streamStarted() {
QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage);
QObject::connect(can, &AbstractStream::eventsMerged, this, &MainWindow::eventsMerged);
QObject::connect(can, &AbstractStream::sourcesUpdated, dbc(), &DBCManager::updateSources);
QObject::connect(can, &AbstractStream::sourcesUpdated, this, &MainWindow::updateLoadSaveMenus);
}
@ -374,7 +373,7 @@ void MainWindow::eventsMerged() {
void MainWindow::save() {
// Save all open DBC files
for (auto &[s, dbc_file] : dbc()->dbc_files) {
for (auto dbc_file : dbc()->allDBCFiles()) {
if (dbc_file->isEmpty()) continue;
saveFile(dbc_file);
}
@ -382,7 +381,7 @@ void MainWindow::save() {
void MainWindow::saveAs() {
// Save as all open DBC files. Should not be called with more than 1 file open
for (auto &[s, dbc_file] : dbc()->dbc_files) {
for (auto dbc_file : dbc()->allDBCFiles()) {
if (dbc_file->isEmpty()) continue;
saveFileAs(dbc_file);
}
@ -390,7 +389,7 @@ void MainWindow::saveAs() {
void MainWindow::autoSave() {
if (!UndoStack::instance()->isClean()) {
for (auto &[_, dbc_file] : dbc()->dbc_files) {
for (auto dbc_file : dbc()->allDBCFiles()) {
if (!dbc_file->filename.isEmpty()) {
dbc_file->autoSave();
}
@ -399,7 +398,7 @@ void MainWindow::autoSave() {
}
void MainWindow::cleanupAutoSaveFile() {
for (auto &[_, dbc_file] : dbc()->dbc_files) {
for (auto dbc_file : dbc()->allDBCFiles()) {
dbc_file->cleanupAutoSaveFile();
}
}
@ -436,9 +435,7 @@ void MainWindow::saveFile(DBCFile *dbc_file) {
}
void MainWindow::saveFileAs(DBCFile *dbc_file) {
auto it = std::find_if(dbc()->dbc_files.begin(), dbc()->dbc_files.end(), [=](auto &f) { return f.second == dbc_file; });
assert(it != dbc()->dbc_files.end());
QString title = tr("Save File (bus: %1)").arg(toString(it->first));
QString title = tr("Save File (bus: %1)").arg(toString(dbc()->sources(dbc_file)));
QString fn = QFileDialog::getSaveFileName(this, title, QDir::cleanPath(settings.last_dir + "/untitled.dbc"), tr("DBC (*.dbc)"));
if (!fn.isEmpty()) {
dbc_file->saveAs(fn);
@ -447,15 +444,9 @@ void MainWindow::saveFileAs(DBCFile *dbc_file) {
}
}
void MainWindow::removeBusFromFile(DBCFile *dbc_file, uint8_t source) {
assert(dbc_file != nullptr);
SourceSet ss = {source, uint8_t(source + 128), uint8_t(source + 192)};
dbc()->removeSourcesFromFile(dbc_file, ss);
}
void MainWindow::saveToClipboard() {
// Copy all open DBC files to clipboard. Should not be called with more than 1 file open
for (auto &[s, dbc_file] : dbc()->dbc_files) {
for (auto dbc_file : dbc()->allDBCFiles()) {
if (dbc_file->isEmpty()) continue;
saveFileToClipboard(dbc_file);
}
@ -480,13 +471,10 @@ void MainWindow::updateLoadSaveMenus() {
// TODO: Support clipboard for multiple files
copy_dbc_to_clipboard->setEnabled(cnt == 1);
QList<uint8_t> sources_sorted = can->sources.toList();
std::sort(sources_sorted.begin(), sources_sorted.end());
manage_dbcs_menu->clear();
manage_dbcs_menu->setEnabled(dynamic_cast<DummyStream *>(can) == nullptr);
for (uint8_t source : sources_sorted) {
for (uint8_t source : can->sources) {
if (source >= 64) continue; // Sent and blocked buses are handled implicitly
SourceSet ss = {source, uint8_t(source + 128), uint8_t(source + 192)};
@ -497,32 +485,26 @@ void MainWindow::updateLoadSaveMenus() {
bus_menu->addAction(tr("Load DBC From Clipboard..."), [=]() { loadFromClipboard(ss, false); });
// Show sub-menu for each dbc for this source.
QStringList bus_menu_fns;
for (auto it : dbc()->dbc_files) {
auto &[src, dbc_file] = it;
if (!src.contains(source) && (src != SOURCE_ALL)) {
continue;
}
QString file_name = "No DBCs loaded";
if (auto dbc_file = dbc()->findDBCFile(source)) {
bus_menu->addSeparator();
bus_menu->addAction(dbc_file->name() + " (" + toString(src) + ")")->setEnabled(false);
bus_menu->addAction(tr("Save..."), [=]() { saveFile(it.second); });
bus_menu->addAction(tr("Save As..."), [=]() { saveFileAs(it.second); });
bus_menu->addAction(tr("Copy to Clipboard..."), [=]() { saveFileToClipboard(it.second); });
bus_menu->addAction(tr("Remove from this bus..."), [=]() { removeBusFromFile(it.second, source); });
bus_menu->addAction(tr("Remove from all buses..."), [=]() { closeFile(it.second); });
bus_menu_fns << dbc_file->name();
bus_menu->addAction(dbc_file->name() + " (" + toString(dbc()->sources(dbc_file)) + ")")->setEnabled(false);
bus_menu->addAction(tr("Save..."), [=]() { saveFile(dbc_file); });
bus_menu->addAction(tr("Save As..."), [=]() { saveFileAs(dbc_file); });
bus_menu->addAction(tr("Copy to Clipboard..."), [=]() { saveFileToClipboard(dbc_file); });
bus_menu->addAction(tr("Remove from this bus..."), [=]() { closeFile(ss); });
bus_menu->addAction(tr("Remove from all buses..."), [=]() { closeFile(dbc_file); });
file_name = dbc_file->name();
}
manage_dbcs_menu->addMenu(bus_menu);
QString bus_menu_title = bus_menu_fns.size() ? bus_menu_fns.join(", ") : "No DBCs loaded";
bus_menu->setTitle(tr("Bus %1 (%2)").arg(source).arg(bus_menu_title));
bus_menu->setTitle(tr("Bus %1 (%2)").arg(source).arg(file_name));
}
QStringList title;
for (auto &[src, dbc_file] : dbc()->dbc_files) {
title.push_back(tr("(%1) %2").arg(toString(src), dbc_file->name()));
for (auto f : dbc()->allDBCFiles()) {
title.push_back(tr("(%1) %2").arg(toString(dbc()->sources(f)), f->name()));
}
setWindowFilePath(title.join(" | "));
}

@ -50,7 +50,6 @@ protected:
void saveFile(DBCFile *dbc_file);
void saveFileAs(DBCFile *dbc_file);
void saveFileToClipboard(DBCFile *dbc_file);
void removeBusFromFile(DBCFile *dbc_file, uint8_t source);
void loadFromClipboard(SourceSet s = SOURCE_ALL, bool close_all = true);
void autoSave();
void cleanupAutoSaveFile();

@ -273,7 +273,7 @@ bool MessageListModel::matchMessage(const MessageId &id, const CanData &data, co
case Column::NAME: {
const auto msg = dbc()->msg(id);
match = re.match(msg ? msg->name : UNTITLED).hasMatch();
match |= msg && std::any_of(msg->sigs.cbegin(), msg->sigs.cend(), [&re](const auto &s) { return re.match(s.name).hasMatch(); });
match |= msg && std::any_of(msg->sigs.cbegin(), msg->sigs.cend(), [&re](const auto &s) { return re.match(s->name).hasMatch(); });
break;
}
case Column::SOURCE:

@ -171,7 +171,6 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r
case Item::Desc: s.val_desc = value.value<ValueDescription>(); break;
default: return false;
}
s.updatePrecision();
bool ret = saveSignal(item->sig, s);
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, Qt::CheckStateRole});
return ret;
@ -249,17 +248,14 @@ void SignalModel::removeSignal(const cabana::Signal *sig) {
}
void SignalModel::handleMsgChanged(MessageId id) {
if (id == msg_id) {
if (id.address == msg_id.address) {
refresh();
}
}
void SignalModel::handleSignalAdded(MessageId id, const cabana::Signal *sig) {
if (id == msg_id) {
int i = 0;
for (; i < root->children.size(); ++i) {
if (sig->start_bit < root->children[i]->sig->start_bit) break;
}
int i = dbc()->msg(msg_id)->indexOf(sig);
beginInsertRows({}, i, i);
insertItem(root.get(), i, sig);
endInsertRows();
@ -348,7 +344,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
path.addRoundedRect(icon_rect, 3, 3);
painter->setPen(item->highlight ? Qt::white : Qt::black);
painter->setFont(label_font);
painter->fillPath(path, getColor(item->sig).darker(item->highlight ? 125 : 0));
painter->fillPath(path, item->sig->color.darker(item->highlight ? 125 : 0));
painter->drawText(icon_rect, Qt::AlignCenter, QString::number(item->row() + 1));
r.setLeft(icon_rect.right() + h_margin * 2);

@ -78,7 +78,7 @@ BO_ 160 message_1: 8 XXX
VAL_ 160 signal_1 0 "disabled" 1.2 "initializing" 2 "fault";
CM_ BO_ 160 "message comment";
CM_ BO_ 160 "message comment" ;
CM_ SG_ 160 signal_1 "signal comment";
CM_ SG_ 160 signal_2 "multiple line comment
1
@ -94,19 +94,19 @@ CM_ SG_ 160 signal_2 "multiple line comment
REQUIRE(msg->sigs.size() == 2);
REQUIRE(file.msg("message_1") != nullptr);
auto &sig_1 = msg->sigs[0];
REQUIRE(sig_1.name == "signal_1");
REQUIRE(sig_1.start_bit == 0);
REQUIRE(sig_1.size == 12);
REQUIRE(sig_1.min == 0);
REQUIRE(sig_1.max == 4095);
REQUIRE(sig_1.unit == "unit");
REQUIRE(sig_1.comment == "signal comment");
REQUIRE(sig_1.val_desc.size() == 3);
REQUIRE(sig_1.val_desc[0] == std::pair<double, QString>{0, "disabled"});
REQUIRE(sig_1.val_desc[1] == std::pair<double, QString>{1.2, "initializing"});
REQUIRE(sig_1.val_desc[2] == std::pair<double, QString>{2, "fault"});
auto sig_1 = msg->sigs[0];
REQUIRE(sig_1->name == "signal_1");
REQUIRE(sig_1->start_bit == 0);
REQUIRE(sig_1->size == 12);
REQUIRE(sig_1->min == 0);
REQUIRE(sig_1->max == 4095);
REQUIRE(sig_1->unit == "unit");
REQUIRE(sig_1->comment == "signal comment");
REQUIRE(sig_1->val_desc.size() == 3);
REQUIRE(sig_1->val_desc[0] == std::pair<double, QString>{0, "disabled"});
REQUIRE(sig_1->val_desc[1] == std::pair<double, QString>{1.2, "initializing"});
REQUIRE(sig_1->val_desc[2] == std::pair<double, QString>{2, "fault"});
auto &sig_2 = msg->sigs[1];
REQUIRE(sig_2.comment == "multiple line comment\n1\n2");
REQUIRE(sig_2->comment == "multiple line comment\n1\n2");
}

@ -24,14 +24,12 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi
for (uint8_t bus : can->sources) {
cb->addItem(QString::number(bus), bus);
}
cb->model()->sort(0);
cb->setCurrentIndex(0);
}
msg_cb = new QComboBox(this);
// TODO: update when src_bus_combo changes
for (auto &[id, msg] : dbc()->getMessages(0)) {
msg_cb->addItem(msg.name, id.address);
for (auto &[address, msg] : dbc()->getMessages(0)) {
msg_cb->addItem(msg.name, address);
}
msg_cb->model()->sort(0);
msg_cb->setCurrentIndex(0);

@ -1,5 +1,6 @@
#include "tools/cabana/util.h"
#include <QColor>
#include <QFontDatabase>
#include <QHelpEvent>
#include <QLocale>
@ -144,17 +145,6 @@ void TabBar::closeTabClicked() {
}
}
QColor getColor(const cabana::Signal *sig) {
float h = 19 * (float)sig->lsb / 64.0;
h = fmod(h, 1.0);
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;
return QColor::fromHsvF(h, s, v);
}
NameValidator::NameValidator(QObject *parent) : QRegExpValidator(QRegExp("^(\\w+)"), parent) {}
QValidator::State NameValidator::validate(QString &input, int &pos) const {
@ -237,10 +227,6 @@ QString toHex(uint8_t byte) {
int num_decimals(double num) {
const QString string = QString::number(num);
const QStringList split = string.split('.');
if (split.size() == 1) {
return 0;
} else {
return split[1].size();
}
auto dot_pos = string.indexOf('.');
return dot_pos == -1 ? 0 : string.size() - dot_pos - 1;
}

@ -2,12 +2,10 @@
#include <cmath>
#include <QAbstractItemView>
#include <QApplication>
#include <QByteArray>
#include <QDateTime>
#include <QDoubleValidator>
#include <QColor>
#include <QFont>
#include <QRegExpValidator>
#include <QStringBuilder>
@ -22,7 +20,7 @@ class LogSlider : public QSlider {
Q_OBJECT
public:
LogSlider(double factor, Qt::Orientation orientation, QWidget *parent = nullptr) : factor(factor), QSlider(orientation, parent) {};
LogSlider(double factor, Qt::Orientation orientation, QWidget *parent = nullptr) : factor(factor), QSlider(orientation, parent) {}
void setRange(double min, double max) {
log_min = factor * std::log10(min);
@ -81,7 +79,6 @@ private:
inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); }
QString toHex(uint8_t byte);
QColor getColor(const cabana::Signal *sig);
class NameValidator : public QRegExpValidator {
Q_OBJECT

Loading…
Cancel
Save