cabana: support ECU node names (#29897)
* support display&edit node name * cleanup * set validator for Node name * modify validator to support multiple receivers * set default to XXX in updateMsg * add DEFAULT_NODE_NAME * Update tools/cabana/commands.h --------- Co-authored-by: Shane Smiskol <shane@smiskol.com> old-commit-hash: c4df40a04a57478883609748c08d1abed539b017
This commit is contained in:
@@ -4,11 +4,13 @@
|
||||
|
||||
// EditMsgCommand
|
||||
|
||||
EditMsgCommand::EditMsgCommand(const MessageId &id, const QString &name, int size, const QString &comment, QUndoCommand *parent)
|
||||
: id(id), new_name(name), new_size(size), new_comment(comment), QUndoCommand(parent) {
|
||||
EditMsgCommand::EditMsgCommand(const MessageId &id, const QString &name, int size,
|
||||
const QString &node, const QString &comment, QUndoCommand *parent)
|
||||
: id(id), new_name(name), new_size(size), new_node(node), new_comment(comment), QUndoCommand(parent) {
|
||||
if (auto msg = dbc()->msg(id)) {
|
||||
old_name = msg->name;
|
||||
old_size = msg->size;
|
||||
old_node = msg->transmitter;
|
||||
old_comment = msg->comment;
|
||||
setText(QObject::tr("edit message %1:%2").arg(name).arg(id.address));
|
||||
} else {
|
||||
@@ -20,11 +22,11 @@ void EditMsgCommand::undo() {
|
||||
if (old_name.isEmpty())
|
||||
dbc()->removeMsg(id);
|
||||
else
|
||||
dbc()->updateMsg(id, old_name, old_size, old_comment);
|
||||
dbc()->updateMsg(id, old_name, old_size, old_node, old_comment);
|
||||
}
|
||||
|
||||
void EditMsgCommand::redo() {
|
||||
dbc()->updateMsg(id, new_name, new_size, new_comment);
|
||||
dbc()->updateMsg(id, new_name, new_size, new_node, new_comment);
|
||||
}
|
||||
|
||||
// RemoveMsgCommand
|
||||
@@ -38,7 +40,7 @@ RemoveMsgCommand::RemoveMsgCommand(const MessageId &id, QUndoCommand *parent) :
|
||||
|
||||
void RemoveMsgCommand::undo() {
|
||||
if (!message.name.isEmpty()) {
|
||||
dbc()->updateMsg(id, message.name, message.size, message.comment);
|
||||
dbc()->updateMsg(id, message.name, message.size, message.transmitter, message.comment);
|
||||
for (auto s : message.getSignals())
|
||||
dbc()->addSignal(id, *s);
|
||||
}
|
||||
@@ -64,7 +66,7 @@ void AddSigCommand::undo() {
|
||||
void AddSigCommand::redo() {
|
||||
if (auto msg = dbc()->msg(id); !msg) {
|
||||
msg_created = true;
|
||||
dbc()->updateMsg(id, dbc()->newMsgName(id), can->lastMessage(id).dat.size(), "");
|
||||
dbc()->updateMsg(id, dbc()->newMsgName(id), can->lastMessage(id).dat.size(), "", "");
|
||||
}
|
||||
signal.name = dbc()->newSignalName(id);
|
||||
signal.max = std::pow(2, signal.size) - 1;
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
|
||||
class EditMsgCommand : public QUndoCommand {
|
||||
public:
|
||||
EditMsgCommand(const MessageId &id, const QString &name, int size, const QString &comment, QUndoCommand *parent = nullptr);
|
||||
EditMsgCommand(const MessageId &id, const QString &name, int size, const QString &node,
|
||||
const QString &comment, QUndoCommand *parent = nullptr);
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
private:
|
||||
const MessageId id;
|
||||
QString old_name, new_name, old_comment, new_comment;
|
||||
QString old_name, new_name, old_comment, new_comment, old_node, new_node;
|
||||
int old_size = 0, new_size = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -78,6 +78,9 @@ QString cabana::Msg::newSignalName() {
|
||||
}
|
||||
|
||||
void cabana::Msg::update() {
|
||||
if (transmitter.isEmpty()) {
|
||||
transmitter = DEFAULT_NODE_NAME;
|
||||
}
|
||||
mask.assign(size, 0x00);
|
||||
multiplexor = nullptr;
|
||||
|
||||
@@ -125,6 +128,9 @@ void cabana::Msg::update() {
|
||||
|
||||
void cabana::Signal::update() {
|
||||
updateMsbLsb(*this);
|
||||
if (receiver_name.isEmpty()) {
|
||||
receiver_name = DEFAULT_NODE_NAME;
|
||||
}
|
||||
|
||||
float h = 19 * (float)lsb / 64.0;
|
||||
h = fmod(h, 1.0);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "opendbc/can/common_dbc.h"
|
||||
|
||||
const QString UNTITLED = "untitled";
|
||||
const QString DEFAULT_NODE_NAME = "XXX";
|
||||
|
||||
struct MessageId {
|
||||
uint8_t source = 0;
|
||||
|
||||
@@ -60,11 +60,12 @@ bool DBCFile::writeContents(const QString &fn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DBCFile::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment) {
|
||||
void DBCFile::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &node, const QString &comment) {
|
||||
auto &m = msgs[id.address];
|
||||
m.address = id.address;
|
||||
m.name = name;
|
||||
m.size = size;
|
||||
m.transmitter = node.isEmpty() ? DEFAULT_NODE_NAME : node;
|
||||
m.comment = comment;
|
||||
}
|
||||
|
||||
@@ -198,7 +199,8 @@ void DBCFile::parse(const QString &content) {
|
||||
QString DBCFile::generateDBC() {
|
||||
QString dbc_string, signal_comment, message_comment, val_desc;
|
||||
for (const auto &[address, m] : msgs) {
|
||||
dbc_string += QString("BO_ %1 %2: %3 %4\n").arg(address).arg(m.name).arg(m.size).arg(m.transmitter.isEmpty() ? "XXX" : m.transmitter);
|
||||
const QString transmitter = m.transmitter.isEmpty() ? DEFAULT_NODE_NAME : m.transmitter;
|
||||
dbc_string += QString("BO_ %1 %2: %3 %4\n").arg(address).arg(m.name).arg(m.size).arg(transmitter);
|
||||
if (!m.comment.isEmpty()) {
|
||||
message_comment += QString("CM_ BO_ %1 \"%2\";\n").arg(address).arg(m.comment);
|
||||
}
|
||||
@@ -221,7 +223,7 @@ QString DBCFile::generateDBC() {
|
||||
.arg(doubleToString(sig->min))
|
||||
.arg(doubleToString(sig->max))
|
||||
.arg(sig->unit)
|
||||
.arg(sig->receiver_name.isEmpty() ? "XXX" : sig->receiver_name);
|
||||
.arg(sig->receiver_name.isEmpty() ? DEFAULT_NODE_NAME : sig->receiver_name);
|
||||
if (!sig->comment.isEmpty()) {
|
||||
signal_comment += QString("CM_ SG_ %1 %2 \"%3\";\n").arg(address).arg(sig->name).arg(sig->comment);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
void cleanupAutoSaveFile();
|
||||
QString generateDBC();
|
||||
|
||||
void updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment);
|
||||
void updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &node, const QString &comment);
|
||||
inline void removeMsg(const MessageId &id) { msgs.erase(id.address); }
|
||||
|
||||
inline const std::map<uint32_t, cabana::Msg> &getMessages() const { return msgs; }
|
||||
|
||||
@@ -82,10 +82,10 @@ void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) {
|
||||
}
|
||||
}
|
||||
|
||||
void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment) {
|
||||
void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &node, const QString &comment) {
|
||||
auto dbc_file = findDBCFile(id);
|
||||
assert(dbc_file); // This should be impossible
|
||||
dbc_file->updateMsg(id, name, size, comment);
|
||||
dbc_file->updateMsg(id, name, size, node, comment);
|
||||
emit msgUpdated(id);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
void updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig);
|
||||
void removeSignal(const MessageId &id, const QString &sig_name);
|
||||
|
||||
void updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment);
|
||||
void updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &node, const QString &comment);
|
||||
void removeMsg(const MessageId &id);
|
||||
|
||||
QString newMsgName(const MessageId &id);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "tools/cabana/commands.h"
|
||||
#include "tools/cabana/mainwin.h"
|
||||
@@ -135,11 +134,12 @@ void DetailWidget::refresh() {
|
||||
for (auto s : binary_view->getOverlappingSignals()) {
|
||||
warnings.push_back(tr("%1 has overlapping bits.").arg(s->name));
|
||||
}
|
||||
name_label->setText(QString("%1 (%2)").arg(msgName(msg_id), msg->transmitter));
|
||||
} else {
|
||||
warnings.push_back(tr("Drag-Select in binary view to create new signal."));
|
||||
name_label->setText(msgName(msg_id));
|
||||
}
|
||||
remove_btn->setEnabled(msg != nullptr);
|
||||
name_label->setText(msgName(msg_id));
|
||||
|
||||
if (!warnings.isEmpty()) {
|
||||
warning_label->setText(warnings.join('\n'));
|
||||
@@ -164,8 +164,8 @@ void DetailWidget::editMsg() {
|
||||
int size = msg ? msg->size : can->lastMessage(msg_id).dat.size();
|
||||
EditMessageDialog dlg(msg_id, msgName(msg_id), size, this);
|
||||
if (dlg.exec()) {
|
||||
UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text().trimmed(),
|
||||
dlg.size_spin->value(), dlg.comment_edit->toPlainText().trimmed()));
|
||||
UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text().trimmed(), dlg.size_spin->value(),
|
||||
dlg.node->text().trimmed(), dlg.comment_edit->toPlainText().trimmed()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,25 +182,24 @@ EditMessageDialog::EditMessageDialog(const MessageId &msg_id, const QString &tit
|
||||
|
||||
form_layout->addRow("", error_label = new QLabel);
|
||||
error_label->setVisible(false);
|
||||
name_edit = new QLineEdit(title, this);
|
||||
form_layout->addRow(tr("Name"), name_edit = new QLineEdit(title, this));
|
||||
name_edit->setValidator(new NameValidator(name_edit));
|
||||
form_layout->addRow(tr("Name"), name_edit);
|
||||
|
||||
size_spin = new QSpinBox(this);
|
||||
form_layout->addRow(tr("Size"), size_spin = new QSpinBox(this));
|
||||
// TODO: limit the maximum?
|
||||
size_spin->setMinimum(1);
|
||||
size_spin->setValue(size);
|
||||
form_layout->addRow(tr("Size"), size_spin);
|
||||
|
||||
form_layout->addRow(tr("Node"), node = new QLineEdit(this));
|
||||
node->setValidator(new NameValidator(name_edit));
|
||||
form_layout->addRow(tr("Comment"), comment_edit = new QTextEdit(this));
|
||||
form_layout->addRow(btn_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel));
|
||||
|
||||
if (auto msg = dbc()->msg(msg_id)) {
|
||||
node->setText(msg->transmitter);
|
||||
comment_edit->setText(msg->comment);
|
||||
}
|
||||
|
||||
btn_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
validateName(name_edit->text());
|
||||
form_layout->addRow(btn_box);
|
||||
|
||||
setFixedWidth(parent->width() * 0.9);
|
||||
connect(name_edit, &QLineEdit::textEdited, this, &EditMessageDialog::validateName);
|
||||
connect(btn_box, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
QString original_name;
|
||||
QDialogButtonBox *btn_box;
|
||||
QLineEdit *name_edit;
|
||||
QLineEdit *node;
|
||||
QTextEdit *comment_edit;
|
||||
QLabel *error_label;
|
||||
QSpinBox *size_spin;
|
||||
|
||||
@@ -36,7 +36,7 @@ SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(p
|
||||
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", "Type", "Multiplex Value", "Extra Info",
|
||||
QString titles[]{"Name", "Size", "Node", "Little Endian", "Signed", "Offset", "Factor", "Type", "Multiplex Value", "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)});
|
||||
@@ -134,6 +134,7 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const {
|
||||
case Item::Sig: return item->sig_val;
|
||||
case Item::Name: return item->sig->name;
|
||||
case Item::Size: return item->sig->size;
|
||||
case Item::Node: return item->sig->receiver_name;
|
||||
case Item::SignalType: return signalTypeToString(item->sig->type);
|
||||
case Item::MultiplexValue: return item->sig->multiplex_value;
|
||||
case Item::Offset: return doubleToString(item->sig->offset);
|
||||
@@ -172,6 +173,7 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r
|
||||
switch (item->type) {
|
||||
case Item::Name: s.name = value.toString(); break;
|
||||
case Item::Size: s.size = value.toInt(); break;
|
||||
case Item::Node: s.receiver_name = value.toString().trimmed(); break;
|
||||
case Item::SignalType: s.type = (cabana::Signal::Type)value.toInt(); break;
|
||||
case Item::MultiplexValue: s.multiplex_value = value.toInt(); break;
|
||||
case Item::Endian: s.is_little_endian = value.toBool(); break;
|
||||
@@ -195,11 +197,11 @@ void SignalModel::showExtraInfo(const QModelIndex &index) {
|
||||
if (item->type == Item::ExtraInfo) {
|
||||
if (!item->parent->extra_expanded) {
|
||||
item->parent->extra_expanded = true;
|
||||
beginInsertRows(index.parent(), 7, 13);
|
||||
beginInsertRows(index.parent(), Item::ExtraInfo - 2, Item::Desc - 2);
|
||||
endInsertRows();
|
||||
} else {
|
||||
item->parent->extra_expanded = false;
|
||||
beginRemoveRows(index.parent(), 7, 13);
|
||||
beginRemoveRows(index.parent(), Item::ExtraInfo - 2, Item::Desc - 2);
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
@@ -267,6 +269,7 @@ void SignalModel::handleSignalRemoved(const cabana::Signal *sig) {
|
||||
|
||||
SignalItemDelegate::SignalItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {
|
||||
name_validator = new NameValidator(this);
|
||||
node_validator = new QRegExpValidator(QRegExp("^\\w+(,\\w+)*$"), this);
|
||||
double_validator = new DoubleValidator(this);
|
||||
|
||||
label_font.setPointSize(8);
|
||||
@@ -382,12 +385,14 @@ 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 ||
|
||||
if (item->type == SignalModel::Item::Name || item->type == SignalModel::Item::Node || item->type == SignalModel::Item::Offset ||
|
||||
item->type == SignalModel::Item::Factor || item->type == SignalModel::Item::MultiplexValue ||
|
||||
item->type == SignalModel::Item::Min || item->type == SignalModel::Item::Max) {
|
||||
QLineEdit *e = new QLineEdit(parent);
|
||||
e->setFrame(false);
|
||||
e->setValidator(item->type == SignalModel::Item::Name ? name_validator : double_validator);
|
||||
if (item->type == SignalModel::Item::Name) e->setValidator(name_validator);
|
||||
else if (item->type == SignalModel::Item::Node) e->setValidator(node_validator);
|
||||
else e->setValidator(double_validator);
|
||||
|
||||
if (item->type == SignalModel::Item::Name) {
|
||||
QCompleter *completer = new QCompleter(dbc()->signalNames());
|
||||
@@ -395,7 +400,6 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie
|
||||
completer->setFilterMode(Qt::MatchContains);
|
||||
e->setCompleter(completer);
|
||||
}
|
||||
|
||||
return e;
|
||||
} else if (item->type == SignalModel::Item::Size) {
|
||||
QSpinBox *spin = new QSpinBox(parent);
|
||||
|
||||
@@ -17,7 +17,7 @@ class SignalModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct Item {
|
||||
enum Type {Root, Sig, Name, Size, Endian, Signed, Offset, Factor, SignalType, MultiplexValue, ExtraInfo, Unit, Comment, Min, Max, Desc };
|
||||
enum Type {Root, Sig, Name, Size, Node, Endian, Signed, Offset, Factor, SignalType, MultiplexValue, ExtraInfo, Unit, Comment, Min, Max, Desc };
|
||||
~Item() { qDeleteAll(children); }
|
||||
inline int row() { return parent->children.indexOf(this); }
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
|
||||
|
||||
QValidator *name_validator, *double_validator;
|
||||
QValidator *name_validator, *double_validator, *node_validator;
|
||||
QFont label_font, minmax_font;
|
||||
const int color_label_width = 18;
|
||||
mutable QSize button_size;
|
||||
|
||||
Reference in New Issue
Block a user