cabana: improve `DBCFile::parse()` (#32160)

improve parse()
pull/32289/head^2
Dean Lee 1 year ago committed by GitHub
parent e095c7c858
commit a6396be53e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 185
      tools/cabana/dbc/dbcfile.cc
  2. 8
      tools/cabana/dbc/dbcfile.h

@ -3,7 +3,6 @@
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QRegularExpression> #include <QRegularExpression>
#include <QTextStream>
DBCFile::DBCFile(const QString &dbc_file_name) { DBCFile::DBCFile(const QString &dbc_file_name) {
QFile file(dbc_file_name); QFile file(dbc_file_name);
@ -76,63 +75,123 @@ cabana::Msg *DBCFile::msg(const QString &name) {
return it != msgs.end() ? &(it->second) : nullptr; return it != msgs.end() ? &(it->second) : nullptr;
} }
cabana::Signal *DBCFile::signal(uint32_t address, const QString name) {
auto m = msg(address);
return m ? (cabana::Signal *)m->sig(name) : nullptr;
}
void DBCFile::parse(const QString &content) { void DBCFile::parse(const QString &content) {
static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))"); msgs.clear();
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+) *\"((?:[^"\\]|\\.)*)\"\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; int line_num = 0;
QString line; QString line;
auto dbc_assert = [&line_num, &line, this](bool condition, const QString &msg = "") {
if (!condition) throw std::runtime_error(QString("[%1:%2]%3: %4").arg(filename).arg(line_num).arg(msg).arg(line).toStdString());
};
auto get_sig = [this](uint32_t address, const QString &name) -> cabana::Signal * {
auto m = (cabana::Msg *)msg(address);
return m ? (cabana::Signal *)m->sig(name) : nullptr;
};
msgs.clear();
QTextStream stream((QString *)&content);
cabana::Msg *current_msg = nullptr; cabana::Msg *current_msg = nullptr;
int multiplexor_cnt = 0; int multiplexor_cnt = 0;
bool seen_first = false; bool seen_first = false;
QTextStream stream((QString *)&content);
while (!stream.atEnd()) { while (!stream.atEnd()) {
++line_num; ++line_num;
QString raw_line = stream.readLine(); QString raw_line = stream.readLine();
line = raw_line.trimmed(); line = raw_line.trimmed();
bool seen = true; bool seen = true;
try {
if (line.startsWith("BO_ ")) { if (line.startsWith("BO_ ")) {
multiplexor_cnt = 0; multiplexor_cnt = 0;
auto match = bo_regexp.match(line); current_msg = parseBO(line);
dbc_assert(match.hasMatch());
auto address = match.captured(1).toUInt();
dbc_assert(msgs.count(address) == 0, QString("Duplicate message address: %1").arg(address));
current_msg = &msgs[address];
current_msg->address = address;
current_msg->name = match.captured(2);
current_msg->size = match.captured(3).toULong();
current_msg->transmitter = match.captured(4).trimmed();
} else if (line.startsWith("SG_ ")) { } else if (line.startsWith("SG_ ")) {
parseSG(line, current_msg, multiplexor_cnt);
} else if (line.startsWith("VAL_ ")) {
parseVAL(line);
} else if (line.startsWith("CM_ BO_")) {
parseCM_BO(line, content, raw_line, stream);
} else if (line.startsWith("CM_ SG_ ")) {
parseCM_SG(line, content, raw_line, stream);
} else {
seen = false;
}
} catch (std::exception &e) {
throw std::runtime_error(QString("[%1:%2]%3: %4").arg(filename).arg(line_num).arg(e.what()).arg(line).toStdString());
}
if (seen) {
seen_first = true;
} else if (!seen_first) {
header += raw_line + "\n";
}
}
for (auto &[_, m] : msgs) {
m.update();
}
}
cabana::Msg *DBCFile::parseBO(const QString &line) {
static QRegularExpression bo_regexp(R"(^BO_ (?<address>\w+) (?<name>\w+) *: (?<size>\w+) (?<transmitter>\w+))");
QRegularExpressionMatch match = bo_regexp.match(line);
if (!match.hasMatch())
throw std::runtime_error("Invalid BO_ line format");
uint32_t address = match.captured("address").toUInt();
if (msgs.count(address) > 0)
throw std::runtime_error(QString("Duplicate message address: %1").arg(address).toStdString());
// Create a new message object
cabana::Msg *msg = &msgs[address];
msg->address = address;
msg->name = match.captured("name");
msg->size = match.captured("size").toULong();
msg->transmitter = match.captured("transmitter").trimmed();
return msg;
}
void DBCFile::parseCM_BO(const QString &line, const QString &content, const QString &raw_line, const QTextStream &stream) {
static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(?<address>\w+) *\"(?<comment>(?:[^"\\]|\\.)*)\"\s*;)");
QString parse_line = line;
if (!parse_line.endsWith("\";")) {
int pos = stream.pos() - raw_line.length() - 1;
parse_line = content.mid(pos, content.indexOf("\";", pos));
}
auto match = msg_comment_regexp.match(parse_line);
if (!match.hasMatch())
throw std::runtime_error("Invalid message comment format");
if (auto m = (cabana::Msg *)msg(match.captured("address").toUInt()))
m->comment = match.captured("comment").trimmed().replace("\\\"", "\"");
}
void DBCFile::parseSG(const QString &line, cabana::Msg *current_msg, int &multiplexor_cnt) {
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]+)\] \"(.*)\" (.*))");
if (!current_msg)
throw std::runtime_error("No Message");
int offset = 0; int offset = 0;
auto match = sg_regexp.match(line); auto match = sg_regexp.match(line);
if (!match.hasMatch()) { if (!match.hasMatch()) {
match = sgm_regexp.match(line); match = sgm_regexp.match(line);
offset = 1; offset = 1;
} }
dbc_assert(match.hasMatch()); if (!match.hasMatch())
dbc_assert(current_msg, "No Message"); throw std::runtime_error("Invalid SG_ line format");
auto name = match.captured(1);
dbc_assert(current_msg->sig(name) == nullptr, "Duplicate signal name"); QString name = match.captured(1);
if (current_msg->sig(name) != nullptr)
throw std::runtime_error("Duplicate signal name");
cabana::Signal s{}; cabana::Signal s{};
if (offset == 1) { if (offset == 1) {
auto indicator = match.captured(2); auto indicator = match.captured(2);
if (indicator == "M") { if (indicator == "M") {
++multiplexor_cnt;
// Only one signal within a single message can be the multiplexer switch. // Only one signal within a single message can be the multiplexer switch.
dbc_assert(++multiplexor_cnt < 2, "Multiple multiplexor"); if (multiplexor_cnt >= 2)
throw std::runtime_error("Multiple multiplexor");
s.type = cabana::Signal::Type::Multiplexor; s.type = cabana::Signal::Type::Multiplexor;
} else { } else {
s.type = cabana::Signal::Type::Multiplexed; s.type = cabana::Signal::Type::Multiplexed;
@ -150,54 +209,42 @@ void DBCFile::parse(const QString &content) {
s.max = match.captured(9 + offset).toDouble(); s.max = match.captured(9 + offset).toDouble();
s.unit = match.captured(10 + offset); s.unit = match.captured(10 + offset);
s.receiver_name = match.captured(11 + offset).trimmed(); s.receiver_name = match.captured(11 + offset).trimmed();
current_msg->sigs.push_back(new cabana::Signal(s)); current_msg->sigs.push_back(new cabana::Signal(s));
} else if (line.startsWith("VAL_ ")) {
auto match = val_regexp.match(line);
dbc_assert(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.toDouble(), desc});
} }
}
} void DBCFile::parseCM_SG(const QString &line, const QString &content, const QString &raw_line, const QTextStream &stream) {
} else if (line.startsWith("CM_ BO_")) { static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"((?:[^"\\]|\\.)*)\"\s*;)");
if (!line.endsWith("\";")) {
int pos = stream.pos() - raw_line.length() - 1; QString parse_line = line;
line = content.mid(pos, content.indexOf("\";", pos)); if (!parse_line.endsWith("\";")) {
}
auto match = msg_comment_regexp.match(line);
dbc_assert(match.hasMatch());
if (auto m = (cabana::Msg *)msg(match.captured(1).toUInt())) {
m->comment = match.captured(2).trimmed().replace("\\\"", "\"");
}
} else if (line.startsWith("CM_ SG_ ")) {
if (!line.endsWith("\";")) {
int pos = stream.pos() - raw_line.length() - 1; int pos = stream.pos() - raw_line.length() - 1;
line = content.mid(pos, content.indexOf("\";", pos)); parse_line = content.mid(pos, content.indexOf("\";", pos));
} }
auto match = sg_comment_regexp.match(line); auto match = sg_comment_regexp.match(parse_line);
dbc_assert(match.hasMatch()); if (!match.hasMatch())
if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { throw std::runtime_error("Invalid CM_ SG_ line format");
if (auto s = signal(match.captured(1).toUInt(), match.captured(2))) {
s->comment = match.captured(3).trimmed().replace("\\\"", "\""); s->comment = match.captured(3).trimmed().replace("\\\"", "\"");
} }
} else {
seen = false;
} }
if (seen) { void DBCFile::parseVAL(const QString &line) {
seen_first = true; static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (\s*[-+]?[0-9]+\s+\".+?\"[^;]*))");
} else if (!seen_first) {
header += raw_line + "\n"; auto match = val_regexp.match(line);
if (!match.hasMatch())
throw std::runtime_error("invalid VAL_ line format");
if (auto s = signal(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.toDouble(), desc});
} }
} }
for (auto &[_, m] : msgs) {
m.update();
} }
} }

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <map> #include <map>
#include <QTextStream>
#include "tools/cabana/dbc/dbc.h" #include "tools/cabana/dbc/dbc.h"
@ -26,6 +27,7 @@ public:
cabana::Msg *msg(uint32_t address); cabana::Msg *msg(uint32_t address);
cabana::Msg *msg(const QString &name); cabana::Msg *msg(const QString &name);
inline cabana::Msg *msg(const MessageId &id) { return msg(id.address); } inline cabana::Msg *msg(const MessageId &id) { return msg(id.address); }
cabana::Signal *signal(uint32_t address, const QString name);
inline QString name() const { return name_.isEmpty() ? "untitled" : name_; } inline QString name() const { return name_.isEmpty() ? "untitled" : name_; }
inline bool isEmpty() const { return msgs.empty() && name_.isEmpty(); } inline bool isEmpty() const { return msgs.empty() && name_.isEmpty(); }
@ -34,6 +36,12 @@ public:
private: private:
void parse(const QString &content); void parse(const QString &content);
cabana::Msg *parseBO(const QString &line);
void parseSG(const QString &line, cabana::Msg *current_msg, int &multiplexor_cnt);
void parseCM_BO(const QString &line, const QString &content, const QString &raw_line, const QTextStream &stream);
void parseCM_SG(const QString &line, const QString &content, const QString &raw_line, const QTextStream &stream);
void parseVAL(const QString &line);
QString header; QString header;
std::map<uint32_t, cabana::Msg> msgs; std::map<uint32_t, cabana::Msg> msgs;
QString name_; QString name_;

Loading…
Cancel
Save