Closes #28
This commit is contained in:
1 parent
a0938cb29c
commit
3dd9230fca
21 files changed
+491
-450
No files matched your search
@@ -19,4 +19,5 @@ HEADERS += \
|
||||
$$PWD/signal_info.h \
|
||||
$$PWD/value_descriptions.h \
|
||||
$$PWD/tree_node.h \
|
||||
$$PWD/text_utils.h \
|
||||
$$PWD/typefactory.h
|
||||
@@ -14,8 +14,7 @@
|
||||
DecodeDatabase DbcDecodeBuilder::Build(const DbcDatabase &source) const {
|
||||
DecodeDatabase result;
|
||||
|
||||
for (std::size_t frameIndex = 0U; frameIndex < source.frames.size(); ++frameIndex) {
|
||||
const FrameInfo &sourceFrame = source.frames[frameIndex];
|
||||
for (const FrameInfo &sourceFrame : source.frames) {
|
||||
DecodeFrame targetFrame;
|
||||
|
||||
targetFrame.name = sourceFrame.name;
|
||||
@@ -27,8 +26,7 @@ DecodeDatabase DbcDecodeBuilder::Build(const DbcDatabase &source) const {
|
||||
targetFrame.transmitter = sourceFrame.transmitter;
|
||||
targetFrame.comment = sourceFrame.comment;
|
||||
|
||||
for (std::size_t signalIndex = 0U; signalIndex < sourceFrame.signals.size(); ++signalIndex) {
|
||||
const SignalInfo &sourceSignal = sourceFrame.signals[signalIndex];
|
||||
for (const SignalInfo &sourceSignal : sourceFrame.signals) {
|
||||
DecodeSignal targetSignal;
|
||||
|
||||
targetSignal.multiplexing = sourceSignal.multiplexing;
|
||||
|
||||
+70
-63
@@ -39,73 +39,80 @@ DecodedFrameValue DbcDecoder::Decode(const DecodeDatabase &database,
|
||||
result.definition = definition;
|
||||
result.valid = true;
|
||||
|
||||
const DecodeSignal *selector = nullptr;
|
||||
std::size_t selectorCount = 0U;
|
||||
for (const DecodeSignal &signal : definition->signals) {
|
||||
if (signal.multiplexing.role == MultiplexRole::Selector) {
|
||||
selector = &signal;
|
||||
++selectorCount;
|
||||
}
|
||||
}
|
||||
const bool selectorDefinitionValid = selectorCount == 1U &&
|
||||
selector->valueType == ValueType::Unsigned && selector->length > 0U && selector->length <= 64U;
|
||||
std::uint64_t selectorValue = 0U;
|
||||
const bool selectorAvailable = selectorDefinitionValid && ExtractUnsigned(frame.data, *selector, selectorValue);
|
||||
|
||||
for (std::size_t signalIndex = 0U; signalIndex < definition->signals.size(); ++signalIndex) {
|
||||
const DecodeSignal &signal = definition->signals[signalIndex];
|
||||
DecodedSignalValue decoded;
|
||||
std::uint64_t unsignedValue = 0U;
|
||||
|
||||
decoded.definition = &signal;
|
||||
|
||||
if (signal.length == 0U || signal.length > 64U ||
|
||||
(signal.multiplexing.role != MultiplexRole::Unconditional && !selectorDefinitionValid)) {
|
||||
result.signals.push_back(decoded);
|
||||
continue;
|
||||
}
|
||||
if (signal.multiplexing.role == MultiplexRole::Branch) {
|
||||
if (selector->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector->length)) {
|
||||
result.signals.push_back(decoded);
|
||||
continue;
|
||||
}
|
||||
if (!selectorAvailable) {
|
||||
decoded.status = SignalDecodeStatus::SelectorUnavailable;
|
||||
result.signals.push_back(decoded);
|
||||
continue;
|
||||
}
|
||||
if (signal.multiplexing.value != selectorValue) {
|
||||
decoded.status = SignalDecodeStatus::Inactive;
|
||||
result.signals.push_back(decoded);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!ExtractUnsigned(frame.data, signal, unsignedValue)) {
|
||||
decoded.status = SignalDecodeStatus::InsufficientPayload;
|
||||
result.signals.push_back(decoded);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (signal.valueType == ValueType::Signed)
|
||||
decoded.rawValue = SignExtend(unsignedValue, signal.length);
|
||||
else
|
||||
decoded.rawValue = unsignedValue;
|
||||
|
||||
double numericValue;
|
||||
if (const std::int64_t *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
|
||||
numericValue = static_cast<double>(*signedValue);
|
||||
else
|
||||
numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
|
||||
decoded.physicalValue = numericValue * signal.factor + signal.offset;
|
||||
decoded.valid = true;
|
||||
decoded.status = SignalDecodeStatus::Valid;
|
||||
|
||||
result.signals.push_back(decoded);
|
||||
}
|
||||
const SelectorState selector = ReadSelector(*definition, frame);
|
||||
for (const DecodeSignal &signal : definition->signals)
|
||||
result.signals.push_back(DecodeOneSignal(signal, frame, selector));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DbcDecoder::SelectorState DbcDecoder::ReadSelector(const DecodeFrame &definition,
|
||||
const RawCanFrame &frame) {
|
||||
SelectorState selector;
|
||||
std::size_t count = 0U;
|
||||
for (const DecodeSignal &signal : definition.signals) {
|
||||
if (signal.multiplexing.role == MultiplexRole::Selector) {
|
||||
selector.definition = &signal;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
if (count != 1U)
|
||||
return selector;
|
||||
|
||||
const DecodeSignal &signal = *selector.definition;
|
||||
selector.valid = signal.valueType == ValueType::Unsigned &&
|
||||
signal.length > 0U && signal.length <= 64U;
|
||||
selector.available = selector.valid && ExtractUnsigned(frame.data, signal, selector.value);
|
||||
return selector;
|
||||
}
|
||||
|
||||
DecodedSignalValue DbcDecoder::DecodeOneSignal(const DecodeSignal &signal,
|
||||
const RawCanFrame &frame,
|
||||
const SelectorState &selector) {
|
||||
DecodedSignalValue decoded;
|
||||
std::uint64_t unsignedValue = 0U;
|
||||
|
||||
decoded.definition = &signal;
|
||||
|
||||
if (signal.length == 0U || signal.length > 64U ||
|
||||
(signal.multiplexing.role != MultiplexRole::Unconditional && !selector.valid)) {
|
||||
return decoded;
|
||||
}
|
||||
if (signal.multiplexing.role == MultiplexRole::Branch) {
|
||||
if (selector.definition->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector.definition->length)) {
|
||||
return decoded;
|
||||
}
|
||||
if (!selector.available) {
|
||||
decoded.status = SignalDecodeStatus::SelectorUnavailable;
|
||||
return decoded;
|
||||
}
|
||||
if (signal.multiplexing.value != selector.value) {
|
||||
decoded.status = SignalDecodeStatus::Inactive;
|
||||
return decoded;
|
||||
}
|
||||
}
|
||||
if (!ExtractUnsigned(frame.data, signal, unsignedValue)) {
|
||||
decoded.status = SignalDecodeStatus::InsufficientPayload;
|
||||
return decoded;
|
||||
}
|
||||
|
||||
if (signal.valueType == ValueType::Signed)
|
||||
decoded.rawValue = SignExtend(unsignedValue, signal.length);
|
||||
else
|
||||
decoded.rawValue = unsignedValue;
|
||||
|
||||
double numericValue;
|
||||
if (const std::int64_t *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
|
||||
numericValue = static_cast<double>(*signedValue);
|
||||
else
|
||||
numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
|
||||
decoded.physicalValue = numericValue * signal.factor + signal.offset;
|
||||
decoded.valid = true;
|
||||
decoded.status = SignalDecodeStatus::Valid;
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
|
||||
const DecodeSignal &signal,
|
||||
std::uint64_t &value) {
|
||||
|
||||
+25
-19
@@ -22,13 +22,11 @@
|
||||
* @brief Raw CAN frame used for runtime or trace decoding.
|
||||
*/
|
||||
struct RawCanFrame {
|
||||
std::uint32_t canId; /**< Normalized CAN ID. */
|
||||
bool isExtended; /**< true for extended frame. */
|
||||
std::vector<std::uint8_t> data; /**< Payload bytes. */
|
||||
std::uint32_t canId = 0U; /**< Normalized CAN ID. */
|
||||
bool isExtended = false; /**< true for extended frame. */
|
||||
std::vector<std::uint8_t> data; /**< Payload bytes. */
|
||||
|
||||
RawCanFrame()
|
||||
: canId(0U), isExtended(false), data() {
|
||||
}
|
||||
RawCanFrame() = default;
|
||||
};
|
||||
|
||||
enum class SignalDecodeStatus {
|
||||
@@ -43,10 +41,10 @@ enum class SignalDecodeStatus {
|
||||
* @brief One decoded signal value.
|
||||
*/
|
||||
struct DecodedSignalValue {
|
||||
const DecodeSignal *definition; /**< Signal definition. */
|
||||
RawSignalValue rawValue; /**< Exact signed or unsigned raw value. */
|
||||
double physicalValue; /**< Converted physical value. */
|
||||
bool valid; /**< true if decoding succeeded. */
|
||||
const DecodeSignal *definition = nullptr; /**< Signal definition. */
|
||||
RawSignalValue rawValue = std::uint64_t(0U); /**< Exact signed or unsigned raw value. */
|
||||
double physicalValue = 0.0; /**< Converted physical value. */
|
||||
bool valid = false; /**< true if decoding succeeded. */
|
||||
SignalDecodeStatus status = SignalDecodeStatus::InvalidDefinition;
|
||||
|
||||
/** Lookup using the raw integer; nullptr for invalid or unmapped values. */
|
||||
@@ -54,22 +52,18 @@ struct DecodedSignalValue {
|
||||
return valid && definition ? FindValueDescription(definition->valueDescriptions, rawValue) : nullptr;
|
||||
}
|
||||
|
||||
DecodedSignalValue()
|
||||
: definition(nullptr), rawValue(std::uint64_t(0U)), physicalValue(0.0), valid(false) {
|
||||
}
|
||||
DecodedSignalValue() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Fully decoded frame.
|
||||
*/
|
||||
struct DecodedFrameValue {
|
||||
const DecodeFrame *definition; /**< Frame definition. */
|
||||
std::vector<DecodedSignalValue> signals; /**< Decoded signal values. */
|
||||
bool valid; /**< true if frame was matched. */
|
||||
const DecodeFrame *definition = nullptr; /**< Frame definition. */
|
||||
std::vector<DecodedSignalValue> signals; /**< Decoded signal values. */
|
||||
bool valid = false; /**< true if frame was matched. */
|
||||
|
||||
DecodedFrameValue()
|
||||
: definition(nullptr), signals(), valid(false) {
|
||||
}
|
||||
DecodedFrameValue() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -98,6 +92,18 @@ public:
|
||||
const RawCanFrame &frame) const;
|
||||
|
||||
private:
|
||||
struct SelectorState {
|
||||
const DecodeSignal *definition = nullptr;
|
||||
bool valid = false;
|
||||
bool available = false;
|
||||
std::uint64_t value = 0U;
|
||||
};
|
||||
|
||||
static SelectorState ReadSelector(const DecodeFrame &definition, const RawCanFrame &frame);
|
||||
static DecodedSignalValue DecodeOneSignal(const DecodeSignal &signal,
|
||||
const RawCanFrame &frame,
|
||||
const SelectorState &selector);
|
||||
|
||||
static bool ExtractUnsigned(const std::vector<std::uint8_t> &data,
|
||||
const DecodeSignal &signal,
|
||||
std::uint64_t &value);
|
||||
|
||||
+2
-27
@@ -12,31 +12,10 @@
|
||||
#include "dbc_parser.h"
|
||||
#include "dbc_statement_handler.h"
|
||||
|
||||
#include <cctype>
|
||||
#include "text_utils.h"
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* @brief Remove leading and trailing spaces.
|
||||
* @param text Input text.
|
||||
* @return Trimmed text.
|
||||
*/
|
||||
std::string TrimText(const std::string &text) {
|
||||
std::string::size_type begin = 0U;
|
||||
while ((begin < text.size()) &&
|
||||
std::isspace(static_cast<unsigned char>(text[begin])))
|
||||
++begin;
|
||||
|
||||
std::string::size_type end = text.size();
|
||||
while ((end > begin) &&
|
||||
std::isspace(static_cast<unsigned char>(text[end - 1U])))
|
||||
--end;
|
||||
|
||||
return text.substr(begin, end - begin);
|
||||
}
|
||||
}// namespace
|
||||
|
||||
DbcDatabase DbcParser::ParseFile(const std::string &filePath) const {
|
||||
std::ifstream input(filePath.c_str());
|
||||
if (!input.is_open())
|
||||
@@ -50,7 +29,7 @@ DbcDatabase DbcParser::ParseFile(const std::string &filePath) const {
|
||||
std::string line;
|
||||
while (std::getline(input, line)) {
|
||||
++lineNumber;
|
||||
line = Trim(line);
|
||||
line = dbc_detail::TrimText(line);
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
@@ -67,7 +46,3 @@ DbcDatabase DbcParser::ParseFile(const std::string &filePath) const {
|
||||
context.ValidateMultiplexing(filePath);
|
||||
return database;
|
||||
}
|
||||
|
||||
std::string DbcParser::Trim(const std::string &text) {
|
||||
return TrimText(text);
|
||||
}
|
||||
+1
-3
@@ -24,11 +24,11 @@
|
||||
* - SG_
|
||||
* - CM_ BO_
|
||||
* - CM_ SG_
|
||||
* - basic M / mN multiplexing
|
||||
* - VAL_ signal value descriptions
|
||||
*
|
||||
* Ignores:
|
||||
* - attributes
|
||||
* - multiplexing
|
||||
* - named VAL_TABLE_ tables
|
||||
*/
|
||||
class DbcParser {
|
||||
@@ -42,8 +42,6 @@ public:
|
||||
*/
|
||||
DbcDatabase ParseFile(const std::string &filePath) const;
|
||||
|
||||
private:
|
||||
static std::string Trim(const std::string &text);
|
||||
};
|
||||
|
||||
#endif /* DBC_PARSER_H */
|
||||
+193
-176
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "dbc_statement_handler.h"
|
||||
#include <cctype>
|
||||
#include "text_utils.h"
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
@@ -13,7 +13,7 @@ namespace {
|
||||
std::uint32_t maximum,
|
||||
const char *field) {
|
||||
std::uint32_t value = 0U;
|
||||
const auto parsed = std::from_chars(text.data(), text.data() + text.size(), value);
|
||||
const std::from_chars_result parsed = std::from_chars(text.data(), text.data() + text.size(), value);
|
||||
if (text.empty() || parsed.ec != std::errc() ||
|
||||
parsed.ptr != text.data() + text.size() || value > maximum)
|
||||
throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
|
||||
@@ -37,27 +37,92 @@ namespace {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove leading and trailing spaces.
|
||||
* @param text Input text.
|
||||
* @return Trimmed text.
|
||||
*/
|
||||
std::string TrimText(const std::string &text) {
|
||||
std::string::size_type begin = 0U;
|
||||
while ((begin < text.size()) &&
|
||||
std::isspace(static_cast<unsigned char>(text[begin])))
|
||||
++begin;
|
||||
Multiplexing ParseMultiplexingMarker(const std::string &marker) {
|
||||
Multiplexing result;
|
||||
if (marker == "M")
|
||||
result.role = MultiplexRole::Selector;
|
||||
else if (!marker.empty()) {
|
||||
if (marker[0] != 'm')
|
||||
throw std::runtime_error("Unsupported multiplexing marker.");
|
||||
const std::string value = marker.substr(1U);
|
||||
const std::from_chars_result parsed =
|
||||
std::from_chars(value.data(), value.data() + value.size(), result.value);
|
||||
if (value.empty() || parsed.ec != std::errc() || parsed.ptr != value.data() + value.size())
|
||||
throw std::runtime_error("Invalid or unsupported multiplexing marker.");
|
||||
result.role = MultiplexRole::Branch;
|
||||
}
|
||||
|
||||
std::string::size_type end = text.size();
|
||||
while ((end > begin) &&
|
||||
std::isspace(static_cast<unsigned char>(text[end - 1U])))
|
||||
--end;
|
||||
|
||||
return text.substr(begin, end - begin);
|
||||
return result;
|
||||
}
|
||||
|
||||
RawSignalValue ParseValueKey(const std::string &number) {
|
||||
RawSignalValue key;
|
||||
if (!number.empty() && number[0] == '-') {
|
||||
std::int64_t value = 0;
|
||||
const std::from_chars_result parsed =
|
||||
std::from_chars(number.data(), number.data() + number.size(), value);
|
||||
if (parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
|
||||
throw std::runtime_error("Invalid VAL_ integer: " + number);
|
||||
key = NormalizeValueKey(RawSignalValue(value));
|
||||
} else {
|
||||
std::uint64_t value = 0;
|
||||
const std::from_chars_result parsed =
|
||||
std::from_chars(number.data(), number.data() + number.size(), value);
|
||||
if (number.empty() || parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
|
||||
throw std::runtime_error("Invalid VAL_ integer: " + number);
|
||||
key = value;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
std::string UnescapeDescription(const std::string "ed) {
|
||||
std::string description;
|
||||
for (std::size_t i = 0; i < quoted.size(); ++i) {
|
||||
if (quoted[i] == '\\')
|
||||
++i;
|
||||
description += quoted[i];
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
FrameInfo *FindUniqueFrame(DbcDatabase &database, std::uint32_t canId, bool isExtended) {
|
||||
FrameInfo *frame = nullptr;
|
||||
for (FrameInfo &candidate : database.frames) {
|
||||
if (candidate.canId == canId && candidate.isExtended == isExtended) {
|
||||
if (frame)
|
||||
throw std::runtime_error("Ambiguous VAL_ frame reference.");
|
||||
frame = &candidate;
|
||||
}
|
||||
}
|
||||
if (!frame)
|
||||
throw std::runtime_error("Unresolved VAL_ frame reference.");
|
||||
return frame;
|
||||
}
|
||||
|
||||
SignalInfo *FindUniqueSignal(FrameInfo &frame, const std::string &signalName) {
|
||||
SignalInfo *signal = nullptr;
|
||||
for (SignalInfo &candidate : frame.signals) {
|
||||
if (candidate.name == signalName) {
|
||||
if (signal)
|
||||
throw std::runtime_error("Ambiguous VAL_ signal reference: " + signalName);
|
||||
signal = &candidate;
|
||||
}
|
||||
}
|
||||
if (!signal)
|
||||
throw std::runtime_error("Unresolved VAL_ signal reference: " + signalName);
|
||||
return signal;
|
||||
}
|
||||
|
||||
std::uint64_t NextSignalBit(std::uint64_t bit, bool isLittleEndian) {
|
||||
if (isLittleEndian)
|
||||
return bit + 1U;
|
||||
// From bit 0, Motorola continues at bit 7 of the next byte (0 -> 15).
|
||||
return bit % 8U == 0U ? bit + 15U : bit - 1U;
|
||||
}
|
||||
|
||||
FrameInfo *FindFrameById(DbcDatabase &, std::uint32_t, bool);
|
||||
SignalInfo *FindSignalByName(FrameInfo &, const std::string &);
|
||||
}// namespace
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
std::vector<std::string> SplitReceivers(const std::string &text) {
|
||||
@@ -66,7 +131,7 @@ namespace {
|
||||
std::istringstream stream(text);
|
||||
|
||||
while (std::getline(stream, token, ',')) {
|
||||
token = TrimText(token);
|
||||
token = dbc_detail::TrimText(token);
|
||||
if (!token.empty())
|
||||
receivers.push_back(token);
|
||||
}
|
||||
@@ -74,14 +139,12 @@ namespace {
|
||||
return receivers;
|
||||
}
|
||||
|
||||
void NormalizeCanId(std::uint32_t rawCanId,
|
||||
std::uint32_t &normalizedCanId,
|
||||
bool &isExtended) {
|
||||
void NormalizeCanId(std::uint32_t rawCanId, std::uint32_t &normalizedCanId, bool &isExtended) {
|
||||
/*
|
||||
* DBC commonly stores extended identifiers with bit 31 set.
|
||||
* Example:
|
||||
* raw id = 0x80000000 | actual_29_bit_id
|
||||
*/
|
||||
* DBC commonly stores extended identifiers with bit 31 set.
|
||||
* Example:
|
||||
* raw id = 0x80000000 | actual_29_bit_id
|
||||
*/
|
||||
if ((rawCanId & 0x80000000U) != 0U) {
|
||||
isExtended = true;
|
||||
normalizedCanId = (rawCanId & 0x1FFFFFFFU);
|
||||
@@ -115,7 +178,7 @@ namespace {
|
||||
return pgn;
|
||||
}
|
||||
|
||||
}// namespace
|
||||
} // namespace
|
||||
|
||||
FrameInfo DbcFrameHandler::ParseFrameLine(const std::string &line) {
|
||||
/*
|
||||
@@ -162,48 +225,50 @@ FrameInfo DbcFrameHandler::ParseFrameLine(const std::string &line) {
|
||||
|
||||
SignalInfo DbcSignalHandler::ParseSignalLine(const std::string &line) {
|
||||
// Match the complete statement before converting any numeric fields.
|
||||
enum Field {
|
||||
NameAndMarker = 1, StartBit, BitLength, ByteOrder, Signedness,
|
||||
Factor, Offset, Minimum, Maximum, Unit, Receivers
|
||||
};
|
||||
static const std::regex syntax(
|
||||
R"dbc(^SG_[ \t]+([^:]+):[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^@ \t]+)[ \t]*@[ \t]*([01])([+-])[ \t]*\([ \t]*([^, \t]+)[ \t]*,[ \t]*([^ )\t]+)[ \t]*\)[ \t]*\[[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^\] \t]+)[ \t]*\][ \t]*"([^"\r\n]*)"[ \t]+([^ \t,]+(?:[ \t]*,[ \t]*[^ \t,]+)*)[ \t]*$)dbc");
|
||||
// Name and optional multiplexing marker.
|
||||
R"dbc(^SG_[ \t]+([^:]+):[ \t]*)dbc"
|
||||
// Bit position, length, byte order and signedness.
|
||||
R"dbc(([^| \t]+)[ \t]*\|[ \t]*([^@ \t]+)[ \t]*@[ \t]*([01])([+-])[ \t]*)dbc"
|
||||
// Scaling factor and offset.
|
||||
R"dbc(\([ \t]*([^, \t]+)[ \t]*,[ \t]*([^ )\t]+)[ \t]*\)[ \t]*)dbc"
|
||||
// Physical range.
|
||||
R"dbc(\[[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^\] \t]+)[ \t]*\][ \t]*)dbc"
|
||||
// Unit and receivers.
|
||||
R"dbc("([^"\r\n]*)"[ \t]+([^ \t,]+(?:[ \t]*,[ \t]*[^ \t,]+)*)[ \t]*$)dbc");
|
||||
std::smatch fields;
|
||||
if (!std::regex_match(line, fields, syntax))
|
||||
throw std::runtime_error("Malformed or unsupported SG_ signal definition.");
|
||||
|
||||
SignalInfo signal;
|
||||
std::istringstream nameFields(fields[1].str());
|
||||
std::istringstream nameFields(fields[NameAndMarker].str());
|
||||
std::string marker;
|
||||
std::string extra;
|
||||
nameFields >> signal.name >> marker;
|
||||
if (signal.name.empty() || (nameFields >> extra))
|
||||
throw std::runtime_error("Invalid signal name or multiplexing marker.");
|
||||
if (marker == "M")
|
||||
signal.multiplexing.role = MultiplexRole::Selector;
|
||||
else if (!marker.empty()) {
|
||||
if (marker[0] != 'm')
|
||||
throw std::runtime_error("Unsupported multiplexing marker.");
|
||||
const std::string value = marker.substr(1U);
|
||||
const std::from_chars_result parsed = std::from_chars(
|
||||
value.data(), value.data() + value.size(), signal.multiplexing.value);
|
||||
if (value.empty() || parsed.ec != std::errc() || parsed.ptr != value.data() + value.size())
|
||||
throw std::runtime_error("Invalid or unsupported multiplexing marker.");
|
||||
signal.multiplexing.role = MultiplexRole::Branch;
|
||||
}
|
||||
signal.multiplexing = ParseMultiplexingMarker(marker);
|
||||
|
||||
signal.startBit = ParseDecimal(fields[2].str(),
|
||||
signal.startBit = ParseDecimal(fields[StartBit].str(),
|
||||
std::numeric_limits<std::uint32_t>::max(), "signal start bit");
|
||||
signal.length = ParseDecimal(fields[3].str(), 64U, "signal length");
|
||||
signal.length = ParseDecimal(fields[BitLength].str(), 64U, "signal length");
|
||||
if (signal.length == 0U)
|
||||
throw std::runtime_error("Signal length must be within 1..64 bits.");
|
||||
signal.isLittleEndian = fields[4].str() == "1";
|
||||
signal.isSigned = fields[5].str() == "-";
|
||||
signal.isLittleEndian = fields[ByteOrder].str() == "1";
|
||||
signal.isSigned = fields[Signedness].str() == "-";
|
||||
|
||||
signal.factor = ParsePhysicalValue(fields[6].str(), "signal factor");
|
||||
signal.offset = ParsePhysicalValue(fields[7].str(), "signal offset");
|
||||
signal.minimum = ParsePhysicalValue(fields[8].str(), "signal minimum");
|
||||
signal.maximum = ParsePhysicalValue(fields[9].str(), "signal maximum");
|
||||
signal.factor = ParsePhysicalValue(fields[Factor].str(), "signal factor");
|
||||
signal.offset = ParsePhysicalValue(fields[Offset].str(), "signal offset");
|
||||
signal.minimum = ParsePhysicalValue(fields[Minimum].str(), "signal minimum");
|
||||
signal.maximum = ParsePhysicalValue(fields[Maximum].str(), "signal maximum");
|
||||
if (signal.minimum > signal.maximum)
|
||||
throw std::runtime_error("Signal minimum exceeds maximum.");
|
||||
signal.unit = fields[10].str();
|
||||
signal.receivers = SplitReceivers(fields[11].str());
|
||||
signal.unit = fields[Unit].str();
|
||||
signal.receivers = SplitReceivers(fields[Receivers].str());
|
||||
return signal;
|
||||
}
|
||||
|
||||
@@ -222,71 +287,52 @@ void DbcCommentHandler::ParseCommentLine(const std::string &line, DbcDatabase &d
|
||||
return;
|
||||
|
||||
stream >> token;
|
||||
if (token != "BO_" && token != "SG_")
|
||||
return;
|
||||
|
||||
if (token == "BO_") {
|
||||
std::uint32_t rawCanId = 0U;
|
||||
std::uint32_t canId = 0U;
|
||||
bool isExtended = false;
|
||||
|
||||
stream >> rawCanId;
|
||||
NormalizeCanId(rawCanId, canId, isExtended);
|
||||
|
||||
const std::string::size_type quoteBegin = line.find('"');
|
||||
const std::string::size_type quoteEnd = line.rfind('"');
|
||||
|
||||
if ((quoteBegin == std::string::npos) ||
|
||||
(quoteEnd == std::string::npos) ||
|
||||
(quoteEnd <= quoteBegin))
|
||||
return;
|
||||
|
||||
FrameInfo *frame = FindFrameById(database, canId, isExtended);
|
||||
if (frame != nullptr)
|
||||
frame->comment = line.substr(quoteBegin + 1U, quoteEnd - quoteBegin - 1U);
|
||||
} else if (token == "SG_") {
|
||||
std::uint32_t rawCanId = 0U;
|
||||
std::uint32_t canId = 0U;
|
||||
bool isExtended = false;
|
||||
std::string signalName;
|
||||
|
||||
stream >> rawCanId;
|
||||
std::uint32_t rawCanId = 0U;
|
||||
std::uint32_t canId = 0U;
|
||||
bool isExtended = false;
|
||||
std::string signalName;
|
||||
stream >> rawCanId;
|
||||
if (token == "SG_")
|
||||
stream >> signalName;
|
||||
NormalizeCanId(rawCanId, canId, isExtended);
|
||||
|
||||
NormalizeCanId(rawCanId, canId, isExtended);
|
||||
const std::string::size_type quoteBegin = line.find('"');
|
||||
const std::string::size_type quoteEnd = line.rfind('"');
|
||||
if (quoteBegin == std::string::npos || quoteEnd == std::string::npos || quoteEnd <= quoteBegin)
|
||||
return;
|
||||
|
||||
const std::string::size_type quoteBegin = line.find('"');
|
||||
const std::string::size_type quoteEnd = line.rfind('"');
|
||||
|
||||
if ((quoteBegin == std::string::npos) ||
|
||||
(quoteEnd == std::string::npos) ||
|
||||
(quoteEnd <= quoteBegin))
|
||||
return;
|
||||
|
||||
FrameInfo *frame = FindFrameById(database, canId, isExtended);
|
||||
if (frame != nullptr) {
|
||||
SignalInfo *signal = FindSignalByName(*frame, signalName);
|
||||
if (signal != nullptr)
|
||||
signal->comment = line.substr(quoteBegin + 1U, quoteEnd - quoteBegin - 1U);
|
||||
}
|
||||
FrameInfo *frame = FindFrameById(database, canId, isExtended);
|
||||
if (frame == nullptr)
|
||||
return;
|
||||
const std::string comment = line.substr(quoteBegin + 1U, quoteEnd - quoteBegin - 1U);
|
||||
if (token == "BO_") {
|
||||
frame->comment = comment;
|
||||
return;
|
||||
}
|
||||
SignalInfo *signal = FindSignalByName(*frame, signalName);
|
||||
if (signal != nullptr)
|
||||
signal->comment = comment;
|
||||
}
|
||||
|
||||
namespace {
|
||||
FrameInfo *FindFrameById(DbcDatabase &database,
|
||||
std::uint32_t canId,
|
||||
bool isExtended) {
|
||||
for (std::size_t index = 0U; index < database.frames.size(); ++index) {
|
||||
if ((database.frames[index].canId == canId) &&
|
||||
(database.frames[index].isExtended == isExtended))
|
||||
return &database.frames[index];
|
||||
for (FrameInfo &frame : database.frames) {
|
||||
if (frame.canId == canId && frame.isExtended == isExtended)
|
||||
return &frame;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SignalInfo *FindSignalByName(FrameInfo &frame, const std::string &signalName) {
|
||||
for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
|
||||
if (frame.signals[index].name == signalName)
|
||||
return &frame.signals[index];
|
||||
for (SignalInfo &signal : frame.signals) {
|
||||
if (signal.name == signalName)
|
||||
return &signal;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -308,10 +354,7 @@ void DbcSignalHandler::Handle(const std::string &line, DbcParseContext &context)
|
||||
for (std::uint32_t index = 0U; index < signal.length; ++index) {
|
||||
if (bit >= payloadBits)
|
||||
throw std::runtime_error("Signal exceeds the frame payload length.");
|
||||
if (signal.isLittleEndian)
|
||||
++bit;
|
||||
else
|
||||
bit = (bit % 8U == 0U) ? bit + 15U : bit - 1U;
|
||||
bit = NextSignalBit(bit, signal.isLittleEndian);
|
||||
}
|
||||
context.currentFrame->signals.push_back(std::move(signal));
|
||||
context.signalLines.back().push_back(context.lineNumber);
|
||||
@@ -335,7 +378,7 @@ bool DbcStatementDispatcher::Dispatch(const std::string &line,
|
||||
std::istringstream stream(line);
|
||||
std::string keyword;
|
||||
stream >> keyword;
|
||||
const auto handler = m_handlers.find(keyword);
|
||||
const HandlerMap::const_iterator handler = m_handlers.find(keyword);
|
||||
if (handler == m_handlers.end())
|
||||
return false;
|
||||
handler->second->Handle(line, context);
|
||||
@@ -348,7 +391,7 @@ void DbcValueDescriptionHandler::Handle(const std::string &line, DbcParseContext
|
||||
std::smatch fields;
|
||||
if (!std::regex_match(line, fields, header))
|
||||
throw std::runtime_error("Malformed or unsupported VAL_ statement.");
|
||||
const auto rawId = ParseDecimal(fields[1].str(), std::numeric_limits<std::uint32_t>::max(), "VAL_ CAN ID");
|
||||
const std::uint32_t rawId = ParseDecimal(fields[1].str(), std::numeric_limits<std::uint32_t>::max(), "VAL_ CAN ID");
|
||||
if ((rawId & 0x60000000U) != 0U)
|
||||
throw std::runtime_error("VAL_ CAN ID exceeds the 29-bit identifier range.");
|
||||
PendingValueDescriptions pending;
|
||||
@@ -360,34 +403,15 @@ void DbcValueDescriptionHandler::Handle(const std::string &line, DbcParseContext
|
||||
if (!std::regex_search(rest, fields, pair))
|
||||
throw std::runtime_error("Malformed VAL_ value/description pair or missing semicolon.");
|
||||
const std::string number = fields[1].str();
|
||||
RawSignalValue key;
|
||||
if (!number.empty() && number[0] == '-') {
|
||||
std::int64_t value = 0;
|
||||
const auto parsed = std::from_chars(number.data(), number.data() + number.size(), value);
|
||||
if (parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
|
||||
throw std::runtime_error("Invalid VAL_ integer: " + number);
|
||||
key = NormalizeValueKey(RawSignalValue(value));
|
||||
} else {
|
||||
std::uint64_t value = 0;
|
||||
const auto parsed = std::from_chars(number.data(), number.data() + number.size(), value);
|
||||
if (number.empty() || parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
|
||||
throw std::runtime_error("Invalid VAL_ integer: " + number);
|
||||
key = value;
|
||||
}
|
||||
std::string description;
|
||||
const std::string quoted = fields[2].str();
|
||||
for (std::size_t i = 0; i < quoted.size(); ++i) {
|
||||
if (quoted[i] == '\\')
|
||||
++i;
|
||||
description += quoted[i];
|
||||
}
|
||||
const RawSignalValue key = ParseValueKey(number);
|
||||
const std::string description = UnescapeDescription(fields[2].str());
|
||||
if (!pending.descriptions.emplace(key, description).second)
|
||||
throw std::runtime_error("Duplicate VAL_ value key: " + number);
|
||||
const auto consumed = static_cast<std::size_t>(fields.length());
|
||||
const std::size_t consumed = static_cast<std::size_t>(fields.length());
|
||||
rest.erase(0, consumed);
|
||||
if (!rest.empty() && rest[0] != ';' && rest[0] != ' ' && rest[0] != '\t')
|
||||
throw std::runtime_error("Missing whitespace between VAL_ pairs.");
|
||||
rest = TrimText(rest);
|
||||
rest = dbc_detail::TrimText(rest);
|
||||
}
|
||||
if (pending.descriptions.empty())
|
||||
throw std::runtime_error("VAL_ requires at least one value/description pair.");
|
||||
@@ -395,29 +419,11 @@ void DbcValueDescriptionHandler::Handle(const std::string &line, DbcParseContext
|
||||
}
|
||||
|
||||
void DbcParseContext::ResolveValueDescriptions(const std::string &filePath) {
|
||||
for (const auto &pending: pendingValues) {
|
||||
for (const PendingValueDescriptions &pending: pendingValues) {
|
||||
try {
|
||||
FrameInfo *frame = nullptr;
|
||||
for (auto &candidate: database.frames) {
|
||||
if (candidate.canId == pending.canId && candidate.isExtended == pending.isExtended) {
|
||||
if (frame)
|
||||
throw std::runtime_error("Ambiguous VAL_ frame reference.");
|
||||
frame = &candidate;
|
||||
}
|
||||
}
|
||||
if (!frame)
|
||||
throw std::runtime_error("Unresolved VAL_ frame reference.");
|
||||
SignalInfo *signal = nullptr;
|
||||
for (auto &candidate: frame->signals) {
|
||||
if (candidate.name == pending.signalName) {
|
||||
if (signal)
|
||||
throw std::runtime_error("Ambiguous VAL_ signal reference: " + pending.signalName);
|
||||
signal = &candidate;
|
||||
}
|
||||
}
|
||||
if (!signal)
|
||||
throw std::runtime_error("Unresolved VAL_ signal reference: " + pending.signalName);
|
||||
for (const auto &entry: pending.descriptions) {
|
||||
FrameInfo *frame = FindUniqueFrame(database, pending.canId, pending.isExtended);
|
||||
SignalInfo *signal = FindUniqueSignal(*frame, pending.signalName);
|
||||
for (const ValueDescriptions::value_type &entry: pending.descriptions) {
|
||||
if (!signal->valueDescriptions.insert(entry).second)
|
||||
throw std::runtime_error("Duplicate VAL_ value key for signal: " + pending.signalName);
|
||||
}
|
||||
@@ -437,14 +443,43 @@ namespace {
|
||||
std::uint64_t bit = signal.startBit;
|
||||
for (std::uint32_t index = 0U; index < signal.length; ++index) {
|
||||
bits.push_back(bit);
|
||||
if (signal.isLittleEndian)
|
||||
++bit;
|
||||
else
|
||||
bit = bit % 8U == 0U ? bit + 15U : bit - 1U;
|
||||
bit = NextSignalBit(bit, signal.isLittleEndian);
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
bool AreMutuallyExclusive(const SignalInfo &first, const SignalInfo &second) {
|
||||
return first.multiplexing.role == MultiplexRole::Branch &&
|
||||
second.multiplexing.role == MultiplexRole::Branch &&
|
||||
first.multiplexing.value != second.multiplexing.value;
|
||||
}
|
||||
|
||||
std::string ValidateBranch(const SignalInfo &signal, const SignalInfo *selector) {
|
||||
if (signal.multiplexing.role != MultiplexRole::Branch)
|
||||
return {};
|
||||
if (selector == nullptr)
|
||||
return "Multiplexed branch has no selector.";
|
||||
if (selector->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector->length))
|
||||
return "Branch value exceeds selector raw range.";
|
||||
return {};
|
||||
}
|
||||
|
||||
const SignalInfo *FindSelector(const FrameInfo &frame,
|
||||
const std::vector<std::size_t> &lines,
|
||||
const std::string &filePath) {
|
||||
const SignalInfo *selector = nullptr;
|
||||
for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
|
||||
const SignalInfo &signal = frame.signals[index];
|
||||
if (signal.multiplexing.role != MultiplexRole::Selector)
|
||||
continue;
|
||||
if (selector != nullptr || signal.isSigned)
|
||||
throw std::runtime_error(filePath + ":" + std::to_string(lines[index]) +
|
||||
": Multiplexing requires one unsigned selector per frame.");
|
||||
selector = &signal;
|
||||
}
|
||||
return selector;
|
||||
}
|
||||
|
||||
bool SignalsOverlap(const SignalInfo &first, const SignalInfo &second) {
|
||||
const std::vector<std::uint64_t> firstBits = SignalBits(first);
|
||||
const std::vector<std::uint64_t> secondBits = SignalBits(second);
|
||||
@@ -461,31 +496,13 @@ namespace {
|
||||
void DbcParseContext::ValidateMultiplexing(const std::string &filePath) const {
|
||||
for (std::size_t frameIndex = 0U; frameIndex < database.frames.size(); ++frameIndex) {
|
||||
const FrameInfo &frame = database.frames[frameIndex];
|
||||
const SignalInfo *selector = nullptr;
|
||||
const SignalInfo *selector = FindSelector(frame, signalLines[frameIndex], filePath);
|
||||
for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
|
||||
const SignalInfo &signal = frame.signals[index];
|
||||
if (signal.multiplexing.role != MultiplexRole::Selector)
|
||||
continue;
|
||||
if (selector != nullptr || signal.isSigned)
|
||||
throw std::runtime_error(filePath + ":" + std::to_string(signalLines[frameIndex][index]) +
|
||||
": Multiplexing requires one unsigned selector per frame.");
|
||||
selector = &signal;
|
||||
}
|
||||
for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
|
||||
const SignalInfo &signal = frame.signals[index];
|
||||
std::string error;
|
||||
if (signal.multiplexing.role == MultiplexRole::Branch) {
|
||||
if (selector == nullptr)
|
||||
error = "Multiplexed branch has no selector.";
|
||||
else if (selector->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector->length))
|
||||
error = "Branch value exceeds selector raw range.";
|
||||
}
|
||||
std::string error = ValidateBranch(signal, selector);
|
||||
for (std::size_t previous = 0U; previous < index && error.empty(); ++previous) {
|
||||
const SignalInfo &other = frame.signals[previous];
|
||||
const bool exclusive = signal.multiplexing.role == MultiplexRole::Branch &&
|
||||
other.multiplexing.role == MultiplexRole::Branch &&
|
||||
signal.multiplexing.value != other.multiplexing.value;
|
||||
if (!exclusive && SignalsOverlap(signal, other))
|
||||
if (!AreMutuallyExclusive(signal, other) && SignalsOverlap(signal, other))
|
||||
error = "Signals overlap without mutually exclusive multiplexing conditions.";
|
||||
}
|
||||
if (!error.empty())
|
||||
|
||||
@@ -83,8 +83,9 @@ public:
|
||||
bool Dispatch(const std::string &line, DbcParseContext &context) const;
|
||||
|
||||
private:
|
||||
using HandlerMap = std::unordered_map<std::string, std::shared_ptr<DbcStatementHandler>>;
|
||||
TypeFactory<std::string, DbcStatementHandler> m_factory;
|
||||
std::unordered_map<std::string, std::shared_ptr<DbcStatementHandler>> m_handlers;
|
||||
HandlerMap m_handlers;
|
||||
};
|
||||
|
||||
#endif /* DBC_STATEMENT_HANDLER_H */
|
||||
@@ -12,15 +12,13 @@
|
||||
#include "dbc_tree_builder.h"
|
||||
|
||||
std::unique_ptr<TreeNode> DbcTreeBuilder::Build(const DbcDatabase &database) const {
|
||||
std::unique_ptr<TreeNode> root(new TreeNode());
|
||||
std::unique_ptr<TreeNode> root = std::make_unique<TreeNode>();
|
||||
|
||||
for (std::size_t frameIndex = 0U; frameIndex < database.frames.size(); ++frameIndex) {
|
||||
const FrameInfo &frame = database.frames[frameIndex];
|
||||
std::unique_ptr<TreeNode> frameNode(new TreeNode(frame));
|
||||
for (const FrameInfo &frame : database.frames) {
|
||||
std::unique_ptr<TreeNode> frameNode = std::make_unique<TreeNode>(frame);
|
||||
|
||||
for (std::size_t signalIndex = 0U; signalIndex < frame.signals.size(); ++signalIndex) {
|
||||
const SignalInfo &signal = frame.signals[signalIndex];
|
||||
std::unique_ptr<TreeNode> signalNode(new TreeNode(signal));
|
||||
for (const SignalInfo &signal : frame.signals) {
|
||||
std::unique_ptr<TreeNode> signalNode = std::make_unique<TreeNode>(signal);
|
||||
frameNode->AddChild(std::move(signalNode));
|
||||
}
|
||||
|
||||
|
||||
+27
-33
@@ -40,54 +40,48 @@ enum class ValueType {
|
||||
*/
|
||||
struct DecodeSignal {
|
||||
Multiplexing multiplexing;
|
||||
std::string name; /**< Signal name. */
|
||||
std::uint32_t startBit; /**< DBC start bit. */
|
||||
std::uint32_t length; /**< Signal length in bits. */
|
||||
ByteOrder byteOrder; /**< Intel or Motorola. */
|
||||
ValueType valueType; /**< Signed or unsigned. */
|
||||
double factor; /**< Scaling factor. */
|
||||
double offset; /**< Physical offset. */
|
||||
double minimum; /**< Minimum physical value. */
|
||||
double maximum; /**< Maximum physical value. */
|
||||
std::string unit; /**< Physical unit. */
|
||||
std::vector<std::string> receivers; /**< Receivers. */
|
||||
ValueDescriptions valueDescriptions; /**< Raw integer state descriptions. */
|
||||
std::string comment; /**< Comment. */
|
||||
std::string name; /**< Signal name. */
|
||||
std::uint32_t startBit = 0U; /**< DBC start bit. */
|
||||
std::uint32_t length = 0U; /**< Signal length in bits. */
|
||||
ByteOrder byteOrder = ByteOrder::Intel; /**< Intel or Motorola. */
|
||||
ValueType valueType = ValueType::Unsigned; /**< Signed or unsigned. */
|
||||
double factor = 1.0; /**< Scaling factor. */
|
||||
double offset = 0.0; /**< Physical offset. */
|
||||
double minimum = 0.0; /**< Minimum physical value. */
|
||||
double maximum = 0.0; /**< Maximum physical value. */
|
||||
std::string unit; /**< Physical unit. */
|
||||
std::vector<std::string> receivers; /**< Receivers. */
|
||||
ValueDescriptions valueDescriptions; /**< Raw integer state descriptions. */
|
||||
std::string comment; /**< Comment. */
|
||||
|
||||
DecodeSignal()
|
||||
: name(), startBit(0U), length(0U), byteOrder(ByteOrder::Intel), valueType(ValueType::Unsigned), factor(1.0), offset(0.0), minimum(0.0), maximum(0.0), unit(), receivers(), comment() {
|
||||
}
|
||||
DecodeSignal() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Runtime-ready frame definition.
|
||||
*/
|
||||
struct DecodeFrame {
|
||||
std::string name; /**< Frame name. */
|
||||
std::uint32_t canId; /**< Normalized CAN ID. */
|
||||
bool isExtended; /**< true for extended frame. */
|
||||
std::uint8_t dlc; /**< Payload length. */
|
||||
std::uint32_t pgn; /**< PGN if available. */
|
||||
bool hasPgn; /**< true if PGN is valid. */
|
||||
std::string transmitter; /**< Transmitter ECU. */
|
||||
std::string comment; /**< Frame comment. */
|
||||
std::vector<DecodeSignal> signals; /**< Signal definitions. */
|
||||
std::string name; /**< Frame name. */
|
||||
std::uint32_t canId = 0U; /**< Normalized CAN ID. */
|
||||
bool isExtended = false; /**< true for extended frame. */
|
||||
std::uint8_t dlc = 0U; /**< Payload length. */
|
||||
std::uint32_t pgn = 0U; /**< PGN if available. */
|
||||
bool hasPgn = false; /**< true if PGN is valid. */
|
||||
std::string transmitter; /**< Transmitter ECU. */
|
||||
std::string comment; /**< Frame comment. */
|
||||
std::vector<DecodeSignal> signals; /**< Signal definitions. */
|
||||
|
||||
DecodeFrame()
|
||||
: name(), canId(0U), isExtended(false), dlc(0U), pgn(0U), hasPgn(false), transmitter(), comment(), signals() {
|
||||
}
|
||||
DecodeFrame() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Key for fast frame lookup.
|
||||
*/
|
||||
struct FrameKey {
|
||||
std::uint32_t canId;
|
||||
bool isExtended;
|
||||
std::uint32_t canId = 0U;
|
||||
bool isExtended = false;
|
||||
|
||||
FrameKey()
|
||||
: canId(0U), isExtended(false) {
|
||||
}
|
||||
FrameKey() = default;
|
||||
|
||||
FrameKey(std::uint32_t id, bool extended)
|
||||
: canId(id), isExtended(extended) {
|
||||
|
||||
+10
-12
@@ -22,19 +22,17 @@
|
||||
* @brief Describes one CAN frame from a DBC file.
|
||||
*/
|
||||
struct FrameInfo {
|
||||
std::string name; /**< Frame name. */
|
||||
std::uint32_t canId; /**< Normalized CAN identifier. */
|
||||
bool isExtended; /**< true for extended frame. */
|
||||
std::uint32_t pgn; /**< J1939 PGN if applicable. */
|
||||
bool hasPgn; /**< true if PGN was derived. */
|
||||
std::uint8_t dlc; /**< Frame payload length. */
|
||||
std::string transmitter; /**< Transmitter ECU name. */
|
||||
std::string comment; /**< Optional frame comment. */
|
||||
std::vector<SignalInfo> signals; /**< Signals contained in the frame. */
|
||||
std::string name; /**< Frame name. */
|
||||
std::uint32_t canId = 0U; /**< Normalized CAN identifier. */
|
||||
bool isExtended = false; /**< true for extended frame. */
|
||||
std::uint32_t pgn = 0U; /**< J1939 PGN if applicable. */
|
||||
bool hasPgn = false; /**< true if PGN was derived. */
|
||||
std::uint8_t dlc = 0U; /**< Frame payload length. */
|
||||
std::string transmitter; /**< Transmitter ECU name. */
|
||||
std::string comment; /**< Optional frame comment. */
|
||||
std::vector<SignalInfo> signals; /**< Signals contained in the frame. */
|
||||
|
||||
FrameInfo()
|
||||
: name(), canId(0U), isExtended(false), pgn(0U), hasPgn(false), dlc(0U), transmitter(), comment(), signals() {
|
||||
}
|
||||
FrameInfo() = default;
|
||||
};
|
||||
|
||||
#endif /* FRAME_INFO_H */
|
||||
+14
-16
@@ -23,23 +23,21 @@
|
||||
*/
|
||||
struct SignalInfo {
|
||||
Multiplexing multiplexing;
|
||||
std::string name; /**< Signal name. */
|
||||
std::uint32_t startBit; /**< Start bit in DBC notation. */
|
||||
std::uint32_t length; /**< Signal length in bits. */
|
||||
bool isLittleEndian; /**< true for Intel, false for Motorola. */
|
||||
bool isSigned; /**< true if signal is signed. */
|
||||
double factor; /**< Scaling factor. */
|
||||
double offset; /**< Physical offset. */
|
||||
double minimum; /**< Minimum physical value. */
|
||||
double maximum; /**< Maximum physical value. */
|
||||
std::string unit; /**< Physical unit. */
|
||||
std::vector<std::string> receivers; /**< Signal receivers. */
|
||||
ValueDescriptions valueDescriptions; /**< Raw integer state descriptions. */
|
||||
std::string comment; /**< Optional signal comment. */
|
||||
std::string name; /**< Signal name. */
|
||||
std::uint32_t startBit = 0U; /**< Start bit in DBC notation. */
|
||||
std::uint32_t length = 0U; /**< Signal length in bits. */
|
||||
bool isLittleEndian = true; /**< true for Intel, false for Motorola. */
|
||||
bool isSigned = false; /**< true if signal is signed. */
|
||||
double factor = 1.0; /**< Scaling factor. */
|
||||
double offset = 0.0; /**< Physical offset. */
|
||||
double minimum = 0.0; /**< Minimum physical value. */
|
||||
double maximum = 0.0; /**< Maximum physical value. */
|
||||
std::string unit; /**< Physical unit. */
|
||||
std::vector<std::string> receivers; /**< Signal receivers. */
|
||||
ValueDescriptions valueDescriptions; /**< Raw integer state descriptions. */
|
||||
std::string comment; /**< Optional signal comment. */
|
||||
|
||||
SignalInfo()
|
||||
: name(), startBit(0U), length(0U), isLittleEndian(true), isSigned(false), factor(1.0), offset(0.0), minimum(0.0), maximum(0.0), unit(), receivers(), comment() {
|
||||
}
|
||||
SignalInfo() = default;
|
||||
};
|
||||
|
||||
#endif /* SIGNAL_INFO_H */
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef DBC_TEXT_UTILS_H
|
||||
#define DBC_TEXT_UTILS_H
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
|
||||
namespace dbc_detail {
|
||||
inline std::string TrimText(const std::string &text) {
|
||||
std::string::size_type begin = 0U;
|
||||
while ((begin < text.size()) &&
|
||||
std::isspace(static_cast<unsigned char>(text[begin])))
|
||||
++begin;
|
||||
|
||||
std::string::size_type end = text.size();
|
||||
while ((end > begin) &&
|
||||
std::isspace(static_cast<unsigned char>(text[end - 1U])))
|
||||
--end;
|
||||
|
||||
return text.substr(begin, end - begin);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+3
-3
@@ -12,15 +12,15 @@
|
||||
#include "tree_node.h"
|
||||
|
||||
TreeNode::TreeNode()
|
||||
: m_type(NodeType::Root), m_name("dbc"), m_children(), m_frame(), m_signal() {
|
||||
: m_type(NodeType::Root), m_name("dbc") {
|
||||
}
|
||||
|
||||
TreeNode::TreeNode(const FrameInfo &frame)
|
||||
: m_type(NodeType::Frame), m_name(frame.name), m_children(), m_frame(new FrameInfo(frame)), m_signal() {
|
||||
: m_type(NodeType::Frame), m_name(frame.name), m_frame(std::make_unique<FrameInfo>(frame)) {
|
||||
}
|
||||
|
||||
TreeNode::TreeNode(const SignalInfo &signal)
|
||||
: m_type(NodeType::Signal), m_name(signal.name), m_children(), m_frame(), m_signal(new SignalInfo(signal)) {
|
||||
: m_type(NodeType::Signal), m_name(signal.name), m_signal(std::make_unique<SignalInfo>(signal)) {
|
||||
}
|
||||
|
||||
void TreeNode::AddChild(std::unique_ptr<TreeNode> child) {
|
||||
|
||||
+2
-2
@@ -48,8 +48,8 @@
|
||||
* factory.registerType<Derived1>("one");
|
||||
* factory.registerType<Derived2>("two");
|
||||
*
|
||||
* auto a = factory.create("one", 10);
|
||||
* auto b = factory.creator("two")(10); // advanced API: get creator function
|
||||
* std::shared_ptr<Base> a = factory.create("one", 10);
|
||||
* std::shared_ptr<Base> b = factory.creator("two")(10); // advanced API: get creator function
|
||||
*
|
||||
* (void)a->get();
|
||||
* (void)b->get();
|
||||
|
||||
@@ -11,7 +11,7 @@ using RawSignalValue = std::variant<std::int64_t, std::uint64_t>;
|
||||
|
||||
/** Canonical keys: negative int64_t, nonnegative uint64_t. */
|
||||
inline RawSignalValue NormalizeValueKey(const RawSignalValue &value) {
|
||||
if (const auto *number = std::get_if<std::int64_t>(&value)) {
|
||||
if (const std::int64_t *number = std::get_if<std::int64_t>(&value)) {
|
||||
if (*number >= 0)
|
||||
return static_cast<std::uint64_t>(*number);
|
||||
}
|
||||
@@ -23,7 +23,7 @@ using ValueDescriptions = std::map<RawSignalValue, std::string>;
|
||||
/** Returns a borrowed string, or nullptr; never converts integers to double. */
|
||||
inline const std::string *FindValueDescription(const ValueDescriptions &descriptions,
|
||||
const RawSignalValue &rawValue) {
|
||||
const auto found = descriptions.find(NormalizeValueKey(rawValue));
|
||||
const ValueDescriptions::const_iterator found = descriptions.find(NormalizeValueKey(rawValue));
|
||||
return found == descriptions.end() ? nullptr : &found->second;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user