summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2022-11-22 12:48:36 +0100
committerIvan Solovev <ivan.solovev@qt.io>2022-12-02 11:26:44 +0100
commit2d9b0002f613795b57257146e17b98a08dff7dfc (patch)
treecedce227bc62975f77fb6966326b3a54f5588374 /src
parent186f34bec49bcdf69817dec016317dd1edcbfa22 (diff)
QCanDbcFileParser: add value description parsing
This commit adds support for the DBC VAL_ command, which defines the textual descriptions for raw values. Task-number: QTBUG-107075 Change-Id: I6d62e8496540755e175f2f98d70a4c2c9b39b18b Reviewed-by: Alex Blasche <alexander.blasche@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src')
-rw-r--r--src/serialbus/qcandbcfileparser.cpp150
-rw-r--r--src/serialbus/qcandbcfileparser.h9
-rw-r--r--src/serialbus/qcandbcfileparser_p.h2
3 files changed, 160 insertions, 1 deletions
diff --git a/src/serialbus/qcandbcfileparser.cpp b/src/serialbus/qcandbcfileparser.cpp
index 9b90397..f5c0492 100644
--- a/src/serialbus/qcandbcfileparser.cpp
+++ b/src/serialbus/qcandbcfileparser.cpp
@@ -47,7 +47,8 @@ QT_BEGIN_NAMESPACE
If the parsing completes successfully, call \l messageDescriptions() to get
a list of the message descriptions that were extracted during the last
- \l parse() call.
+ \l parse() call. Call \l valueDescriptions() to get the textual descriptions
+ of signal raw values, if they are available.
Use the static \l uniqueIdDescription() function to get a
\l QCanUniqueIdDescription for the DBC format.
@@ -78,6 +79,7 @@ QT_BEGIN_NAMESPACE
\li \c {SIG_VALTYPE_} - signal type description.
\li \c {SG_MUL_VAL_} - extended multiplexing description.
\li \c {CM_} - comments (only for message and signal descriptions).
+ \li \c {VAL_} - textual descriptions for raw signal values.
\endlist
Lines starting from other keywords are simply ignored.
@@ -86,6 +88,40 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \typealias QCanDbcFileParser::ValueDescriptions
+
+ This is a type alias for \c {QHash<quint32, QString>}.
+
+ The keys of the hash represent raw signal values, and the values of the
+ hash represent corresponding string descriptions.
+*/
+
+/*!
+ \typealias QCanDbcFileParser::SignalValueDescriptions
+
+ This is a type alias for \c {QHash<QString, ValueDescriptions>}.
+
+ The keys of the hash represent signal names, and the values of the
+ hash contain the corresponding \l QCanDbcFileParser::ValueDescriptions
+ entries.
+
+ \sa QCanDbcFileParser::ValueDescriptions
+*/
+
+/*!
+ \typealias QCanDbcFileParser::MessageValueDescriptions
+
+ This is a type alias for
+ \c {QHash<QtCanBus::UniqueId, SignalValueDescriptions>}.
+
+ The keys of the hash represent message unique ids, and the values of the
+ hash contain the corresponding \l QCanDbcFileParser::SignalValueDescriptions
+ entries.
+
+ \sa QCanDbcFileParser::SignalValueDescriptions
+*/
+
+/*!
\enum QCanDbcFileParser::Error
This enum represents the possible errors that can happen during the parsing
@@ -169,6 +205,27 @@ QList<QCanMessageDescription> QCanDbcFileParser::messageDescriptions() const
}
/*!
+ Returns the textual descriptions for signal raw values.
+
+ DBC supports the possibility to provide textual descriptions to signal raw
+ values. If such data exists in the parsed DBC file(s), it can be accessed
+ using this function.
+
+ The textual descriptions are unique for a certain signal within a specific
+ message, so the returned structure contains the information about the
+ message unique id and the signal name, as well as the actual value
+ descriptions.
+
+ \sa QCanDbcFileParser::MessageValueDescriptions,
+ QCanDbcFileParser::SignalValueDescriptions,
+ QCanDbcFileParser::ValueDescriptions
+*/
+QCanDbcFileParser::MessageValueDescriptions QCanDbcFileParser::valueDescriptions() const
+{
+ return d->m_valueDescriptions;
+}
+
+/*!
Returns the last error which occurred during the parsing.
\sa errorString(), parse()
@@ -236,6 +293,7 @@ static constexpr auto kSignalDef = "SG_ "_L1;
static constexpr auto kSigValTypeDef = "SIG_VALTYPE_ "_L1;
static constexpr auto kCommentDef = "CM_ "_L1;
static constexpr auto kExtendedMuxDef = "SG_MUL_VAL_ "_L1;
+static constexpr auto kValDef = "VAL_ "_L1;
static constexpr auto kUnsignedIntRegExp = "\\d+"_L1;
static constexpr auto kDoubleRegExp = "[+-]?\\d+(.\\d+([eE][+-]?\\d+)?)?"_L1;
@@ -260,6 +318,7 @@ void QCanDbcFileParserPrivate::reset()
m_seenExtraData = false;
m_currentMessage = {};
m_messageDescriptions.clear();
+ m_valueDescriptions.clear();
}
/*!
@@ -340,6 +399,10 @@ bool QCanDbcFileParserPrivate::processLine(const QStringView line)
m_seenExtraData = true;
addCurrentMessage();
parseExtendedMux(data);
+ } else if (data.startsWith(kValDef)) {
+ m_seenExtraData = true;
+ addCurrentMessage();
+ parseValueDescriptions(data);
}
return true;
}
@@ -781,6 +844,91 @@ void QCanDbcFileParserPrivate::parseExtendedMux(const QStringView data)
m_messageDescriptions.insert(uid, messageDesc);
}
+void QCanDbcFileParserPrivate::parseValueDescriptions(const QStringView data)
+{
+ // The regexp should match the following pattern:
+ // VAL_ message_id signal_name { value_description };
+ // Here the value_description is defined as follows
+ // value_description = unsigned_int char_string
+
+ // %1 valDef
+ // %2 maybeSpace
+ // %3 unsignedInt
+ // %4 oneOrMoreSpace
+ // %5 DbcIdentifier
+ // %6 charStr
+ const QString regExStr =
+ "%1%2(?<messageId>%3)%4(?<signalName>%5)(%4%3%4\"(%6)\")+%2;"_L1.
+ arg(kValDef, kMaybeSpaceRegExp, kUnsignedIntRegExp, kOneOrMoreSpaceRegExp,
+ kDbcIdentRegExp, kCharStrRegExp);
+
+ const QRegularExpression valueDescRegExp(regExStr);
+
+ const auto match = valueDescRegExp.matchView(data);
+ if (!match.hasMatch()) {
+ m_lineOffset = data.size();
+ addWarning(QObject::tr("Failed to parse value description from string %1").arg(data));
+ return;
+ }
+
+ m_lineOffset = match.capturedEnd(0);
+
+ bool ok = false;
+ const auto uid = match.capturedView(u"messageId"_s).toUInt(&ok);
+ if (!ok) {
+ addWarning(QObject::tr("Failed to parse value description from string %1").arg(data));
+ return;
+ }
+
+ // Check if the message exists
+ const auto messageDesc = m_messageDescriptions.value(uid);
+ if (!messageDesc.isValid()) {
+ addWarning(QObject::tr("Value description for message id %1 is skipped because "
+ "the message description is not found").arg(uid));
+ return;
+ }
+
+ // Check if the signal exists within the message
+ const QString signalName = match.captured(u"signalName"_s);
+ if (!messageDesc.signalDescriptionForName(signalName).isValid()) {
+ addWarning(QObject::tr("Value description for signal %1 and message id %2 is skipped "
+ "because the signal description is not found").
+ arg(signalName).arg(uid));
+ return;
+ }
+
+ // We can have an arbitrary amount of value descriptions, so we can't use
+ // capture groups to capture them. But we know that they follow a specific
+ // pattern (because the full string matched the regexp). So we need to parse
+ // the rest of the matched string manually
+ const auto totalEnd = match.capturedEnd(0); // including the ';'
+ const auto signalNameEnd = match.capturedEnd(u"signalName"_s);
+ const auto len = totalEnd - signalNameEnd - 1;
+ if (len > 0) {
+ auto signalDescriptionsView = data.sliced(signalNameEnd, len).trimmed();
+ while (signalDescriptionsView.size()) {
+ const auto spacePos = signalDescriptionsView.indexOf(u' ');
+ if (spacePos == -1)
+ break;
+ bool ok = false;
+ const auto value = signalDescriptionsView.sliced(0, spacePos).toUInt(&ok);
+ if (!ok)
+ break;
+ const auto firstQuotePos = signalDescriptionsView.indexOf(u'"', spacePos + 1);
+ if (firstQuotePos == -1)
+ break;
+ const auto nextQuotePos = signalDescriptionsView.indexOf(u'"', firstQuotePos + 1);
+ if (nextQuotePos == -1)
+ break;
+ const auto description = signalDescriptionsView.sliced(
+ firstQuotePos + 1, nextQuotePos - firstQuotePos - 1);
+
+ m_valueDescriptions[uid][signalName].insert(value, description.toString());
+ signalDescriptionsView = signalDescriptionsView.sliced(nextQuotePos + 1).trimmed();
+ }
+ }
+}
+
void QCanDbcFileParserPrivate::postProcessSignalMultiplexing()
{
// For the case of simple multiplexing we need to do the following for
diff --git a/src/serialbus/qcandbcfileparser.h b/src/serialbus/qcandbcfileparser.h
index 2186c7d..7869fb4 100644
--- a/src/serialbus/qcandbcfileparser.h
+++ b/src/serialbus/qcandbcfileparser.h
@@ -6,6 +6,7 @@
#include <QtCore/QList>
+#include <QtSerialBus/qcancommondefinitions.h>
#include <QtSerialBus/qtserialbusglobal.h>
#include <memory>
@@ -25,6 +26,13 @@ public:
ParseError
};
+ // The DBC protocol uses unsinged_integer to describe the supported values.
+ // Do we need to use QVariant instead of quint32? Or qint64 for better BC
+ // guarantees?
+ using ValueDescriptions = QHash<quint32, QString>;
+ using SignalValueDescriptions = QHash<QString, ValueDescriptions>;
+ using MessageValueDescriptions = QHash<QtCanBus::UniqueId, SignalValueDescriptions>;
+
QCanDbcFileParser();
~QCanDbcFileParser();
@@ -32,6 +40,7 @@ public:
bool parse(const QStringList &fileNames);
QList<QCanMessageDescription> messageDescriptions() const;
+ MessageValueDescriptions valueDescriptions() const;
Error error() const;
QString errorString() const;
diff --git a/src/serialbus/qcandbcfileparser_p.h b/src/serialbus/qcandbcfileparser_p.h
index 1a698b2..6381b39 100644
--- a/src/serialbus/qcandbcfileparser_p.h
+++ b/src/serialbus/qcandbcfileparser_p.h
@@ -37,6 +37,7 @@ public:
void parseSignalType(const QStringView data);
void parseComment(const QStringView data);
void parseExtendedMux(const QStringView data);
+ void parseValueDescriptions(const QStringView data);
void postProcessSignalMultiplexing();
void addWarning(QString &&warning);
@@ -53,6 +54,7 @@ public:
bool m_seenExtraData = false;
QCanMessageDescription m_currentMessage;
QHash<QtCanBus::UniqueId, QCanMessageDescription> m_messageDescriptions;
+ QCanDbcFileParser::MessageValueDescriptions m_valueDescriptions;
};
QT_END_NAMESPACE