diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..248ec09 --- /dev/null +++ b/.clang-format @@ -0,0 +1,65 @@ +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 8 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/dbc_database.h b/dbc_database.h index 43342a3..350c426 100644 --- a/dbc_database.h +++ b/dbc_database.h @@ -20,7 +20,7 @@ * @brief Parsed DBC content stored in a simple internal form. */ struct DbcDatabase { - std::vector frames; /**< All frames found in the DBC file. */ + std::vector frames; /**< All frames found in the DBC file. */ }; #endif /* DBC_DATABASE_H */ diff --git a/dbc_decode_builder.cpp b/dbc_decode_builder.cpp index 85b8c38..7acbd4d 100644 --- a/dbc_decode_builder.cpp +++ b/dbc_decode_builder.cpp @@ -11,46 +11,46 @@ #include "dbc_decode_builder.h" -DecodeDatabase DbcDecodeBuilder::Build (const DbcDatabase &source) const { - DecodeDatabase result; +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]; - DecodeFrame targetFrame; + for (std::size_t frameIndex = 0U; frameIndex < source.frames.size(); ++frameIndex) { + const FrameInfo &sourceFrame = source.frames[frameIndex]; + DecodeFrame targetFrame; - targetFrame.name = sourceFrame.name; - targetFrame.canId = sourceFrame.canId; - targetFrame.isExtended = sourceFrame.isExtended; - targetFrame.dlc = sourceFrame.dlc; - targetFrame.pgn = sourceFrame.pgn; - targetFrame.hasPgn = sourceFrame.hasPgn; - targetFrame.transmitter = sourceFrame.transmitter; - targetFrame.comment = sourceFrame.comment; + targetFrame.name = sourceFrame.name; + targetFrame.canId = sourceFrame.canId; + targetFrame.isExtended = sourceFrame.isExtended; + targetFrame.dlc = sourceFrame.dlc; + targetFrame.pgn = sourceFrame.pgn; + targetFrame.hasPgn = sourceFrame.hasPgn; + 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]; - DecodeSignal targetSignal; + for (std::size_t signalIndex = 0U; signalIndex < sourceFrame.signals.size(); ++signalIndex) { + const SignalInfo &sourceSignal = sourceFrame.signals[signalIndex]; + DecodeSignal targetSignal; - targetSignal.name = sourceSignal.name; - targetSignal.startBit = sourceSignal.startBit; - targetSignal.length = sourceSignal.length; - targetSignal.byteOrder = sourceSignal.isLittleEndian ? ByteOrder::Intel : ByteOrder::Motorola; - targetSignal.valueType = sourceSignal.isSigned ? ValueType::Signed : ValueType::Unsigned; - targetSignal.factor = sourceSignal.factor; - targetSignal.offset = sourceSignal.offset; - targetSignal.minimum = sourceSignal.minimum; - targetSignal.maximum = sourceSignal.maximum; - targetSignal.unit = sourceSignal.unit; - targetSignal.receivers = sourceSignal.receivers; - targetSignal.comment = sourceSignal.comment; + targetSignal.name = sourceSignal.name; + targetSignal.startBit = sourceSignal.startBit; + targetSignal.length = sourceSignal.length; + targetSignal.byteOrder = sourceSignal.isLittleEndian ? ByteOrder::Intel : ByteOrder::Motorola; + targetSignal.valueType = sourceSignal.isSigned ? ValueType::Signed : ValueType::Unsigned; + targetSignal.factor = sourceSignal.factor; + targetSignal.offset = sourceSignal.offset; + targetSignal.minimum = sourceSignal.minimum; + targetSignal.maximum = sourceSignal.maximum; + targetSignal.unit = sourceSignal.unit; + targetSignal.receivers = sourceSignal.receivers; + targetSignal.comment = sourceSignal.comment; - targetFrame.signals.push_back (targetSignal); + targetFrame.signals.push_back(targetSignal); + } + + result.frames.push_back(targetFrame); + result.frameIndexByKey[FrameKey(targetFrame.canId, targetFrame.isExtended)] = + result.frames.size() - 1U; } - result.frames.push_back (targetFrame); - result.frameIndexByKey[FrameKey (targetFrame.canId, targetFrame.isExtended)] = - result.frames.size() - 1U; - } - - return result; + return result; } diff --git a/dbc_decode_builder.h b/dbc_decode_builder.h index 5fa1fa3..737b192 100644 --- a/dbc_decode_builder.h +++ b/dbc_decode_builder.h @@ -19,13 +19,13 @@ * @brief Converts parsed DBC data into runtime decode database. */ class DbcDecodeBuilder { - public: +public: /** * @brief Build runtime decode database. * @param source Parsed DBC database. * @return Runtime-ready decode database. */ - DecodeDatabase Build (const DbcDatabase &source) const; + DecodeDatabase Build(const DbcDatabase &source) const; }; #endif /* DBC_DECODE_BUILDER_H */ diff --git a/dbc_decoder.cpp b/dbc_decoder.cpp index c1faaa1..00258aa 100644 --- a/dbc_decoder.cpp +++ b/dbc_decoder.cpp @@ -11,104 +11,105 @@ #include "dbc_decoder.h" -const DecodeFrame *DbcDecoder::FindFrame (const DecodeDatabase &database, - std::uint32_t canId, - bool isExtended) const { - const FrameKey key (canId, isExtended); - const std::unordered_map::const_iterator it = - database.frameIndexByKey.find (key); +const DecodeFrame *DbcDecoder::FindFrame(const DecodeDatabase &database, + std::uint32_t canId, + bool isExtended) const { + const FrameKey key(canId, isExtended); + const std::unordered_map::const_iterator it = + database.frameIndexByKey.find(key); - if (it == database.frameIndexByKey.end()) - return nullptr; + if (it == database.frameIndexByKey.end()) + return nullptr; - const std::size_t index = it->second; - if (index >= database.frames.size()) - return nullptr; + const std::size_t index = it->second; + if (index >= database.frames.size()) + return nullptr; - return &database.frames[index]; + return &database.frames[index]; } -DecodedFrameValue DbcDecoder::Decode (const DecodeDatabase &database, - const RawCanFrame &frame) const { - DecodedFrameValue result; - const DecodeFrame *definition = FindFrame (database, frame.canId, frame.isExtended); +DecodedFrameValue DbcDecoder::Decode(const DecodeDatabase &database, + const RawCanFrame &frame) const { + DecodedFrameValue result; + const DecodeFrame *definition = FindFrame(database, frame.canId, frame.isExtended); - if (definition == nullptr) - return result; + if (definition == nullptr) + return result; - result.definition = definition; - result.valid = true; + result.definition = definition; + result.valid = true; - for (std::size_t signalIndex = 0U; signalIndex < definition->signals.size(); ++signalIndex) { - const DecodeSignal &signal = definition->signals[signalIndex]; - DecodedSignalValue decoded; - std::uint64_t unsignedValue = 0U; + 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; + decoded.definition = &signal; - if (!ExtractUnsigned (frame.data, signal, unsignedValue)) { - decoded.valid = false; - result.signals.push_back (decoded); - continue; + if (!ExtractUnsigned(frame.data, signal, unsignedValue)) { + decoded.valid = false; + result.signals.push_back(decoded); + continue; + } + + if (signal.valueType == ValueType::Signed) + decoded.rawValue = SignExtend(unsignedValue, signal.length); + else + decoded.rawValue = unsignedValue; + + decoded.physicalValue = + std::visit([&signal](auto rawValue) { + return (static_cast(rawValue) * signal.factor) + signal.offset; + }, + decoded.rawValue); + decoded.valid = true; + + result.signals.push_back(decoded); } - if (signal.valueType == ValueType::Signed) - decoded.rawValue = SignExtend (unsignedValue, signal.length); - else - decoded.rawValue = unsignedValue; - - decoded.physicalValue = - std::visit ([&signal] (auto rawValue) { - return (static_cast (rawValue) * signal.factor) + signal.offset; - }, decoded.rawValue); - decoded.valid = true; - - result.signals.push_back (decoded); - } - - return result; + return result; } -bool DbcDecoder::ExtractUnsigned (const std::vector &data, - const DecodeSignal &signal, - std::uint64_t &value) { - if ((signal.length == 0U) || (signal.length > 64U)) - return false; +bool DbcDecoder::ExtractUnsigned(const std::vector &data, + const DecodeSignal &signal, + std::uint64_t &value) { + if ((signal.length == 0U) || (signal.length > 64U)) + return false; - if (signal.byteOrder == ByteOrder::Intel) - return ExtractIntel (data, signal.startBit, signal.length, value); + if (signal.byteOrder == ByteOrder::Intel) + return ExtractIntel(data, signal.startBit, signal.length, value); - return ExtractMotorola (data, signal.startBit, signal.length, value); + return ExtractMotorola(data, signal.startBit, signal.length, value); } -bool DbcDecoder::ExtractIntel (const std::vector &data, - std::uint32_t startBit, - std::uint32_t length, - std::uint64_t &value) { - value = 0U; +bool DbcDecoder::ExtractIntel(const std::vector &data, + std::uint32_t startBit, + std::uint32_t length, + std::uint64_t &value) { + value = 0U; - for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) { - const std::uint32_t absoluteBit = startBit + bitIndex; - const std::uint32_t byteIndex = absoluteBit / 8U; - const std::uint32_t bitInByte = absoluteBit % 8U; + for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) { + const std::uint32_t absoluteBit = startBit + bitIndex; + const std::uint32_t byteIndex = absoluteBit / 8U; + const std::uint32_t bitInByte = absoluteBit % 8U; - if (byteIndex >= data.size()) - return false; + if (byteIndex >= data.size()) + return false; - const std::uint64_t bitValue = - (static_cast ((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex); + const std::uint64_t bitValue = + (static_cast((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex); - value |= bitValue; - } + value |= bitValue; + } - return true; + return true; } -bool DbcDecoder::ExtractMotorola (const std::vector &data, - std::uint32_t startBit, - std::uint32_t length, - std::uint64_t &value) { - /* +bool DbcDecoder::ExtractMotorola(const std::vector &data, + std::uint32_t startBit, + std::uint32_t length, + std::uint64_t &value) { + /* * DBC Motorola bit numbering: * - startBit points to the most significant bit of the signal * - inside a byte, bit numbering goes 7..0 @@ -116,40 +117,41 @@ bool DbcDecoder::ExtractMotorola (const std::vector &data, * Example: a signal starting at 7 follows 7..0, 15..8, 23..16. */ - value = 0U; + value = 0U; - std::size_t byteIndex = startBit / 8U; - std::uint32_t bitInByte = startBit % 8U; + std::size_t byteIndex = startBit / 8U; + std::uint32_t bitInByte = startBit % 8U; - for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) { - if (byteIndex >= data.size()) - return false; + for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) { + if (byteIndex >= data.size()) + return false; - value <<= 1U; - value |= static_cast ((data[byteIndex] >> bitInByte) & 0x01U); + value <<= 1U; + value |= static_cast((data[byteIndex] >> bitInByte) & 0x01U); - if (bitInByte == 0U) { - ++byteIndex; - bitInByte = 7U; - } else - --bitInByte; - } + if (bitInByte == 0U) { + ++byteIndex; + bitInByte = 7U; + } else + --bitInByte; + } - return true; + return true; } -std::int64_t DbcDecoder::SignExtend (std::uint64_t value, std::uint32_t bitLength) { - if ((bitLength == 0U) || (bitLength > 64U)) - return 0; +std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) { + if ((bitLength == 0U) || (bitLength > 64U)) + return 0; - const std::uint64_t signMask = std::uint64_t (1U) << (bitLength - 1U); - const std::uint64_t valueMask = (bitLength == 64U) - ? ~std::uint64_t (0U) : (std::uint64_t (1U) << bitLength) - 1U; - value &= valueMask; + const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U); + const std::uint64_t valueMask = (bitLength == 64U) + ? ~std::uint64_t(0U) + : (std::uint64_t(1U) << bitLength) - 1U; + value &= valueMask; - if ((value & signMask) == 0U) - return static_cast (value); + if ((value & signMask) == 0U) + return static_cast(value); - // The complemented magnitude fits int64_t, including for INT64_MIN. - return -1 - static_cast ((~value) & valueMask); + // The complemented magnitude fits int64_t, including for INT64_MIN. + return -1 - static_cast((~value) & valueMask); } diff --git a/dbc_decoder.h b/dbc_decoder.h index 6b7a3ef..56d1bc0 100644 --- a/dbc_decoder.h +++ b/dbc_decoder.h @@ -12,9 +12,9 @@ #ifndef DBC_DECODER_H #define DBC_DECODER_H -#include #include #include +#include #include "decode_database.h" @@ -22,54 +22,47 @@ * @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 data; /**< Payload bytes. */ + std::uint32_t canId; /**< Normalized CAN ID. */ + bool isExtended; /**< true for extended frame. */ + std::vector data; /**< Payload bytes. */ - RawCanFrame() - : canId (0U) - , isExtended (false) - , data() { - } + RawCanFrame() + : canId(0U), isExtended(false), data() { + } }; /** * @brief One decoded signal value. */ struct DecodedSignalValue { - const DecodeSignal *definition; /**< Signal definition. */ - std::variant rawValue; /**< Exact signed or unsigned raw value. */ - double physicalValue; /**< Converted physical value. */ - bool valid; /**< true if decoding succeeded. */ + const DecodeSignal *definition; /**< Signal definition. */ + std::variant rawValue; /**< Exact signed or unsigned raw value. */ + double physicalValue; /**< Converted physical value. */ + bool valid; /**< true if decoding succeeded. */ - DecodedSignalValue() - : definition (nullptr) - , rawValue (std::uint64_t (0U)) - , physicalValue (0.0) - , valid (false) { - } + DecodedSignalValue() + : definition(nullptr), rawValue(std::uint64_t(0U)), physicalValue(0.0), valid(false) { + } }; /** * @brief Fully decoded frame. */ struct DecodedFrameValue { - const DecodeFrame *definition; /**< Frame definition. */ - std::vector signals; /**< Decoded signal values. */ - bool valid; /**< true if frame was matched. */ + const DecodeFrame *definition; /**< Frame definition. */ + std::vector signals; /**< Decoded signal values. */ + bool valid; /**< true if frame was matched. */ - DecodedFrameValue() - : definition (nullptr) - , signals() - , valid (false) { - } + DecodedFrameValue() + : definition(nullptr), signals(), valid(false) { + } }; /** * @brief Runtime CAN decoder using prebuilt decode database. */ class DbcDecoder { - public: +public: /** * @brief Find frame definition by CAN ID. * @param database Runtime decode database. @@ -77,9 +70,9 @@ class DbcDecoder { * @param isExtended true for extended frame. * @return Pointer to frame definition or nullptr. */ - const DecodeFrame *FindFrame (const DecodeDatabase &database, - std::uint32_t canId, - bool isExtended) const; + const DecodeFrame *FindFrame(const DecodeDatabase &database, + std::uint32_t canId, + bool isExtended) const; /** * @brief Decode one raw CAN frame. @@ -87,25 +80,25 @@ class DbcDecoder { * @param frame Raw CAN frame. * @return Decoded frame value. */ - DecodedFrameValue Decode (const DecodeDatabase &database, - const RawCanFrame &frame) const; + DecodedFrameValue Decode(const DecodeDatabase &database, + const RawCanFrame &frame) const; - private: - static bool ExtractUnsigned (const std::vector &data, - const DecodeSignal &signal, - std::uint64_t &value); +private: + static bool ExtractUnsigned(const std::vector &data, + const DecodeSignal &signal, + std::uint64_t &value); - static bool ExtractIntel (const std::vector &data, - std::uint32_t startBit, - std::uint32_t length, - std::uint64_t &value); + static bool ExtractIntel(const std::vector &data, + std::uint32_t startBit, + std::uint32_t length, + std::uint64_t &value); - static bool ExtractMotorola (const std::vector &data, - std::uint32_t startBit, - std::uint32_t length, - std::uint64_t &value); + static bool ExtractMotorola(const std::vector &data, + std::uint32_t startBit, + std::uint32_t length, + std::uint64_t &value); - static std::int64_t SignExtend (std::uint64_t value, std::uint32_t bitLength); + static std::int64_t SignExtend(std::uint64_t value, std::uint32_t bitLength); }; #endif /* DBC_DECODER_H */ diff --git a/dbc_parser.cpp b/dbc_parser.cpp index 3882efe..5a697fc 100644 --- a/dbc_parser.cpp +++ b/dbc_parser.cpp @@ -12,59 +12,59 @@ #include "dbc_parser.h" #include "dbc_statement_handler.h" +#include #include #include -#include 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 (text[begin]))) - ++begin; + std::string TrimText(const std::string &text) { + std::string::size_type begin = 0U; + while ((begin < text.size()) && + std::isspace(static_cast(text[begin]))) + ++begin; - std::string::size_type end = text.size(); - while ((end > begin) && - std::isspace (static_cast (text[end - 1U]))) - --end; + std::string::size_type end = text.size(); + while ((end > begin) && + std::isspace(static_cast(text[end - 1U]))) + --end; - return text.substr (begin, end - begin); - } -} - -DbcDatabase DbcParser::ParseFile (const std::string &filePath) const { - std::ifstream input (filePath.c_str()); - if (!input.is_open()) - throw std::runtime_error ("Failed to open DBC file: " + filePath); - - DbcDatabase database; - DbcParseContext context {database, nullptr}; - const DbcStatementDispatcher dispatcher; - - std::size_t lineNumber = 0U; - std::string line; - while (std::getline (input, line)) { - ++lineNumber; - line = Trim (line); - if (line.empty()) - continue; - - try { - dispatcher.Dispatch (line, context); - } catch (const std::exception &error) { - throw std::runtime_error (filePath + ":" + std::to_string (lineNumber) + - ": " + error.what()); + return text.substr(begin, end - begin); } - } +}// namespace - return database; +DbcDatabase DbcParser::ParseFile(const std::string &filePath) const { + std::ifstream input(filePath.c_str()); + if (!input.is_open()) + throw std::runtime_error("Failed to open DBC file: " + filePath); + + DbcDatabase database; + DbcParseContext context{database, nullptr}; + const DbcStatementDispatcher dispatcher; + + std::size_t lineNumber = 0U; + std::string line; + while (std::getline(input, line)) { + ++lineNumber; + line = Trim(line); + if (line.empty()) + continue; + + try { + dispatcher.Dispatch(line, context); + } catch (const std::exception &error) { + throw std::runtime_error(filePath + ":" + std::to_string(lineNumber) + + ": " + error.what()); + } + } + + return database; } -std::string DbcParser::Trim (const std::string &text) { - return TrimText (text); +std::string DbcParser::Trim(const std::string &text) { + return TrimText(text); } diff --git a/dbc_parser.h b/dbc_parser.h index fa58508..8cd39fa 100644 --- a/dbc_parser.h +++ b/dbc_parser.h @@ -31,7 +31,7 @@ * - value tables */ class DbcParser { - public: +public: /** * @brief Parse DBC file. * @param filePath Path to input file. @@ -39,10 +39,10 @@ class DbcParser { * @throws std::runtime_error on file or parse errors. * Line parse errors include the file path and one-based line number. */ - DbcDatabase ParseFile (const std::string &filePath) const; + DbcDatabase ParseFile(const std::string &filePath) const; - private: - static std::string Trim (const std::string &text); +private: + static std::string Trim(const std::string &text); }; #endif /* DBC_PARSER_H */ diff --git a/dbc_statement_handler.cpp b/dbc_statement_handler.cpp index cfda956..53d726a 100644 --- a/dbc_statement_handler.cpp +++ b/dbc_statement_handler.cpp @@ -1,323 +1,323 @@ // SPDX-License-Identifier: MIT #include "dbc_statement_handler.h" -#include -#include #include #include +#include #include #include -#include +#include +#include namespace { - std::uint32_t ParseDecimal (const std::string &text, - 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); - if (text.empty() || parsed.ec != std::errc() || - parsed.ptr != text.data() + text.size() || value > maximum) - throw std::runtime_error (std::string ("Invalid ") + field + ": " + text); - return value; - } + std::uint32_t ParseDecimal(const std::string &text, + 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); + if (text.empty() || parsed.ec != std::errc() || + parsed.ptr != text.data() + text.size() || value > maximum) + throw std::runtime_error(std::string("Invalid ") + field + ": " + text); + 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 (text[begin]))) - ++begin; + std::string TrimText(const std::string &text) { + std::string::size_type begin = 0U; + while ((begin < text.size()) && + std::isspace(static_cast(text[begin]))) + ++begin; - std::string::size_type end = text.size(); - while ((end > begin) && - std::isspace (static_cast (text[end - 1U]))) - --end; + std::string::size_type end = text.size(); + while ((end > begin) && + std::isspace(static_cast(text[end - 1U]))) + --end; - return text.substr (begin, end - begin); - } - FrameInfo *FindFrameById (DbcDatabase &, std::uint32_t, bool); - SignalInfo *FindSignalByName (FrameInfo &, const std::string &); -} + return text.substr(begin, end - begin); + } + FrameInfo *FindFrameById(DbcDatabase &, std::uint32_t, bool); + SignalInfo *FindSignalByName(FrameInfo &, const std::string &); +}// namespace namespace { -std::vector SplitReceivers (const std::string &text) { - std::vector receivers; - std::string token; - std::istringstream stream (text); + std::vector SplitReceivers(const std::string &text) { + std::vector receivers; + std::string token; + std::istringstream stream(text); - while (std::getline (stream, token, ',')) { - token = TrimText (token); - if (!token.empty()) - receivers.push_back (token); - } + while (std::getline(stream, token, ',')) { + token = TrimText(token); + if (!token.empty()) + receivers.push_back(token); + } - return receivers; -} + 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 */ - if ((rawCanId & 0x80000000U) != 0U) { - isExtended = true; - normalizedCanId = (rawCanId & 0x1FFFFFFFU); - } else { - isExtended = (rawCanId > 0x7FFU); - normalizedCanId = rawCanId; - } -} + if ((rawCanId & 0x80000000U) != 0U) { + isExtended = true; + normalizedCanId = (rawCanId & 0x1FFFFFFFU); + } else { + isExtended = (rawCanId > 0x7FFU); + normalizedCanId = rawCanId; + } + } -std::uint32_t TryExtractPgn (std::uint32_t canId, bool isExtended, bool &hasPgn) { - hasPgn = false; + std::uint32_t TryExtractPgn(std::uint32_t canId, bool isExtended, bool &hasPgn) { + hasPgn = false; - if (!isExtended) - return 0U; + if (!isExtended) + return 0U; - if ((canId & 0x1FFFFFFFU) != canId) - return 0U; + if ((canId & 0x1FFFFFFFU) != canId) + return 0U; - const std::uint32_t pf = (canId >> 16U) & 0xFFU; - const std::uint32_t ps = (canId >> 8U) & 0xFFU; - const std::uint32_t dp = (canId >> 24U) & 0x01U; + const std::uint32_t pf = (canId >> 16U) & 0xFFU; + const std::uint32_t ps = (canId >> 8U) & 0xFFU; + const std::uint32_t dp = (canId >> 24U) & 0x01U; - std::uint32_t pgn = 0U; + std::uint32_t pgn = 0U; - if (pf < 240U) - pgn = (dp << 16U) | (pf << 8U); - else - pgn = (dp << 16U) | (pf << 8U) | ps; + if (pf < 240U) + pgn = (dp << 16U) | (pf << 8U); + else + pgn = (dp << 16U) | (pf << 8U) | ps; - hasPgn = true; - return pgn; -} + hasPgn = true; + return pgn; + } -} +}// namespace -FrameInfo DbcFrameHandler::ParseFrameLine (const std::string &line) { - /* +FrameInfo DbcFrameHandler::ParseFrameLine(const std::string &line) { + /* * Example: * BO_ 256 EngineData: 8 EEC1 */ - std::istringstream stream (line); - std::string keyword; - std::string idText; - if (!(stream >> keyword >> idText) || keyword != "BO_") - throw std::runtime_error ("Missing CAN ID in frame definition."); + std::istringstream stream(line); + std::string keyword; + std::string idText; + if (!(stream >> keyword >> idText) || keyword != "BO_") + throw std::runtime_error("Missing CAN ID in frame definition."); - const std::uint32_t rawCanId = ParseDecimal ( - idText, std::numeric_limits::max(), "CAN ID"); - // Only bit 31 may accompany the actual 29-bit identifier. - if ((rawCanId & 0x60000000U) != 0U) - throw std::runtime_error ("CAN ID exceeds the 29-bit identifier range."); + const std::uint32_t rawCanId = ParseDecimal( + idText, std::numeric_limits::max(), "CAN ID"); + // Only bit 31 may accompany the actual 29-bit identifier. + if ((rawCanId & 0x60000000U) != 0U) + throw std::runtime_error("CAN ID exceeds the 29-bit identifier range."); - std::string nameText; - if (!std::getline (stream, nameText, ':') || stream.eof()) - throw std::runtime_error ("Missing ':' in frame definition."); - std::istringstream nameStream (nameText); - FrameInfo frame; - std::string extra; - if (!(nameStream >> frame.name) || (nameStream >> extra)) - throw std::runtime_error ("Missing or invalid frame name."); + std::string nameText; + if (!std::getline(stream, nameText, ':') || stream.eof()) + throw std::runtime_error("Missing ':' in frame definition."); + std::istringstream nameStream(nameText); + FrameInfo frame; + std::string extra; + if (!(nameStream >> frame.name) || (nameStream >> extra)) + throw std::runtime_error("Missing or invalid frame name."); - std::string lengthText; - if (!(stream >> lengthText)) - throw std::runtime_error ("Missing payload length in frame definition."); - frame.dlc = static_cast (ParseDecimal ( - lengthText, std::numeric_limits::max(), "payload length")); - if (!(stream >> frame.transmitter)) - throw std::runtime_error ("Missing transmitter in frame definition."); - if (stream >> extra) - throw std::runtime_error ("Unexpected trailing field in frame definition: " + extra); + std::string lengthText; + if (!(stream >> lengthText)) + throw std::runtime_error("Missing payload length in frame definition."); + frame.dlc = static_cast(ParseDecimal( + lengthText, std::numeric_limits::max(), "payload length")); + if (!(stream >> frame.transmitter)) + throw std::runtime_error("Missing transmitter in frame definition."); + if (stream >> extra) + throw std::runtime_error("Unexpected trailing field in frame definition: " + extra); - NormalizeCanId (rawCanId, frame.canId, frame.isExtended); - frame.pgn = TryExtractPgn (frame.canId, frame.isExtended, frame.hasPgn); + NormalizeCanId(rawCanId, frame.canId, frame.isExtended); + frame.pgn = TryExtractPgn(frame.canId, frame.isExtended, frame.hasPgn); - return frame; + return frame; } -SignalInfo DbcSignalHandler::ParseSignalLine (const std::string &line) { - // Match the complete statement before converting any numeric fields. - 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"); - std::smatch fields; - if (!std::regex_match (line, fields, syntax)) - throw std::runtime_error ("Malformed or unsupported SG_ signal definition."); +SignalInfo DbcSignalHandler::ParseSignalLine(const std::string &line) { + // Match the complete statement before converting any numeric fields. + 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"); + std::smatch fields; + if (!std::regex_match(line, fields, syntax)) + throw std::runtime_error("Malformed or unsupported SG_ signal definition."); - SignalInfo signal; - signal.name = TrimText (fields[1].str()); - if (signal.name.empty() || signal.name.find_first_of (" \t\r\n") != std::string::npos) - throw std::runtime_error ("Invalid signal name or unsupported multiplexing syntax."); + SignalInfo signal; + signal.name = TrimText(fields[1].str()); + if (signal.name.empty() || signal.name.find_first_of(" \t\r\n") != std::string::npos) + throw std::runtime_error("Invalid signal name or unsupported multiplexing syntax."); - signal.startBit = ParseDecimal (fields[2].str(), - std::numeric_limits::max(), "signal start bit"); - signal.length = ParseDecimal (fields[3].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.startBit = ParseDecimal(fields[2].str(), + std::numeric_limits::max(), "signal start bit"); + signal.length = ParseDecimal(fields[3].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() == "-"; - const auto parsePhysical = [] (const std::string &text, const char *field) { - static const std::regex number ( - R"(^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$)"); - if (!std::regex_match (text, number)) - throw std::runtime_error (std::string ("Invalid ") + field + ": " + text); - std::size_t consumed = 0U; - double value; - try { - value = std::stod (text, &consumed); - } catch (const std::exception &) { - throw std::runtime_error (std::string ("Invalid ") + field + ": " + text); - } - if (consumed != text.size() || !std::isfinite (value)) - throw std::runtime_error (std::string ("Invalid ") + field + ": " + text); - return value; - }; - signal.factor = parsePhysical (fields[6].str(), "signal factor"); - signal.offset = parsePhysical (fields[7].str(), "signal offset"); - signal.minimum = parsePhysical (fields[8].str(), "signal minimum"); - signal.maximum = parsePhysical (fields[9].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()); - return signal; + const auto parsePhysical = [](const std::string &text, const char *field) { + static const std::regex number( + R"(^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$)"); + if (!std::regex_match(text, number)) + throw std::runtime_error(std::string("Invalid ") + field + ": " + text); + std::size_t consumed = 0U; + double value; + try { + value = std::stod(text, &consumed); + } catch (const std::exception &) { + throw std::runtime_error(std::string("Invalid ") + field + ": " + text); + } + if (consumed != text.size() || !std::isfinite(value)) + throw std::runtime_error(std::string("Invalid ") + field + ": " + text); + return value; + }; + signal.factor = parsePhysical(fields[6].str(), "signal factor"); + signal.offset = parsePhysical(fields[7].str(), "signal offset"); + signal.minimum = parsePhysical(fields[8].str(), "signal minimum"); + signal.maximum = parsePhysical(fields[9].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()); + return signal; } -void DbcCommentHandler::ParseCommentLine (const std::string &line, DbcDatabase &database) { - /* +void DbcCommentHandler::ParseCommentLine(const std::string &line, DbcDatabase &database) { + /* * Examples: * CM_ BO_ 256 "Frame comment"; * CM_ SG_ 256 EngineSpeed "Signal comment"; */ - std::istringstream stream (line); - std::string token; - stream >> token; + std::istringstream stream(line); + std::string token; + stream >> token; - if (token != "CM_") - return; + if (token != "CM_") + return; - stream >> token; + stream >> token; - if (token == "BO_") { - std::uint32_t rawCanId = 0U; - std::uint32_t canId = 0U; - bool isExtended = false; + if (token == "BO_") { + std::uint32_t rawCanId = 0U; + std::uint32_t canId = 0U; + bool isExtended = false; - stream >> rawCanId; - NormalizeCanId (rawCanId, canId, isExtended); + stream >> rawCanId; + NormalizeCanId(rawCanId, canId, isExtended); - const std::string::size_type quoteBegin = line.find ('"'); - const std::string::size_type quoteEnd = line.rfind ('"'); + 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; + 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; + 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; - stream >> signalName; + stream >> rawCanId; + 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 ('"'); + 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; + 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) { + SignalInfo *signal = FindSignalByName(*frame, signalName); + if (signal != nullptr) + signal->comment = line.substr(quoteBegin + 1U, quoteEnd - quoteBegin - 1U); + } } - } } 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]; - } + 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]; + } - return nullptr; + 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]; + } + + return nullptr; + } +}// namespace + +void DbcFrameHandler::Handle(const std::string &line, DbcParseContext &context) const { + context.database.frames.push_back(ParseFrameLine(line)); + context.currentFrame = &context.database.frames.back(); } -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]; - } - - return nullptr; -} +void DbcSignalHandler::Handle(const std::string &line, DbcParseContext &context) const { + if (context.currentFrame == nullptr) + throw std::runtime_error("Signal found before any frame definition."); + SignalInfo signal = ParseSignalLine(line); + const std::uint64_t payloadBits = static_cast(context.currentFrame->dlc) * 8U; + std::uint64_t bit = signal.startBit; + 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; + } + context.currentFrame->signals.push_back(std::move(signal)); } -void DbcFrameHandler::Handle (const std::string &line, DbcParseContext &context) const { - context.database.frames.push_back (ParseFrameLine (line)); - context.currentFrame = &context.database.frames.back(); -} - -void DbcSignalHandler::Handle (const std::string &line, DbcParseContext &context) const { - if (context.currentFrame == nullptr) - throw std::runtime_error ("Signal found before any frame definition."); - SignalInfo signal = ParseSignalLine (line); - const std::uint64_t payloadBits = static_cast (context.currentFrame->dlc) * 8U; - std::uint64_t bit = signal.startBit; - 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; - } - context.currentFrame->signals.push_back (std::move (signal)); -} - -void DbcCommentHandler::Handle (const std::string &line, DbcParseContext &context) const { - if (line.compare (0U, 4U, "CM_ ") == 0) - ParseCommentLine (line, context.database); +void DbcCommentHandler::Handle(const std::string &line, DbcParseContext &context) const { + if (line.compare(0U, 4U, "CM_ ") == 0) + ParseCommentLine(line, context.database); } DbcStatementDispatcher::DbcStatementDispatcher() { - RegisterType ("BO_"); - RegisterType ("SG_"); - RegisterType ("CM_"); + RegisterType("BO_"); + RegisterType("SG_"); + RegisterType("CM_"); } -bool DbcStatementDispatcher::Dispatch (const std::string &line, - DbcParseContext &context) const { - std::istringstream stream (line); - std::string keyword; - stream >> keyword; - const auto handler = m_handlers.find (keyword); - if (handler == m_handlers.end()) - return false; - handler->second->Handle (line, context); - return true; +bool DbcStatementDispatcher::Dispatch(const std::string &line, + DbcParseContext &context) const { + std::istringstream stream(line); + std::string keyword; + stream >> keyword; + const auto handler = m_handlers.find(keyword); + if (handler == m_handlers.end()) + return false; + handler->second->Handle(line, context); + return true; } diff --git a/dbc_statement_handler.h b/dbc_statement_handler.h index fccea45..ffd5a8d 100644 --- a/dbc_statement_handler.h +++ b/dbc_statement_handler.h @@ -9,54 +9,57 @@ /** Mutable state belonging to one file parse. Handlers do not retain it. */ struct DbcParseContext { - DbcDatabase &database; - FrameInfo *currentFrame = nullptr; + DbcDatabase &database; + FrameInfo *currentFrame = nullptr; }; class DbcStatementHandler { - public: +public: virtual ~DbcStatementHandler() = default; - virtual void Handle (const std::string &line, DbcParseContext &context) const = 0; + virtual void Handle(const std::string &line, DbcParseContext &context) const = 0; }; class DbcFrameHandler : public DbcStatementHandler { - public: - void Handle (const std::string &line, DbcParseContext &context) const override; - private: - static FrameInfo ParseFrameLine (const std::string &line); +public: + void Handle(const std::string &line, DbcParseContext &context) const override; + +private: + static FrameInfo ParseFrameLine(const std::string &line); }; class DbcSignalHandler : public DbcStatementHandler { - public: - void Handle (const std::string &line, DbcParseContext &context) const override; - private: - static SignalInfo ParseSignalLine (const std::string &line); +public: + void Handle(const std::string &line, DbcParseContext &context) const override; + +private: + static SignalInfo ParseSignalLine(const std::string &line); }; class DbcCommentHandler : public DbcStatementHandler { - public: - void Handle (const std::string &line, DbcParseContext &context) const override; - private: - static void ParseCommentLine (const std::string &line, DbcDatabase &database); +public: + void Handle(const std::string &line, DbcParseContext &context) const override; + +private: + static void ParseCommentLine(const std::string &line, DbcDatabase &database); }; /** Exact-key dispatch to handlers created once per registration via TypeFactory. */ class DbcStatementDispatcher { - public: +public: DbcStatementDispatcher(); - template - void RegisterType (const std::string &keyword) { - m_factory.registerType (keyword); - m_handlers.insert_or_assign (keyword, m_factory.create (keyword)); + template + void RegisterType(const std::string &keyword) { + m_factory.registerType(keyword); + m_handlers.insert_or_assign(keyword, m_factory.create(keyword)); } /** Returns false for an unregistered keyword; input must be trimmed. */ - bool Dispatch (const std::string &line, DbcParseContext &context) const; + bool Dispatch(const std::string &line, DbcParseContext &context) const; - private: +private: TypeFactory m_factory; - std::unordered_map > m_handlers; + std::unordered_map> m_handlers; }; #endif /* DBC_STATEMENT_HANDLER_H */ diff --git a/dbc_tree_builder.cpp b/dbc_tree_builder.cpp index 122104c..9013ae5 100644 --- a/dbc_tree_builder.cpp +++ b/dbc_tree_builder.cpp @@ -11,21 +11,21 @@ #include "dbc_tree_builder.h" -std::unique_ptr DbcTreeBuilder::Build (const DbcDatabase &database) const { - std::unique_ptr root (new TreeNode()); +std::unique_ptr DbcTreeBuilder::Build(const DbcDatabase &database) const { + std::unique_ptr root(new TreeNode()); - for (std::size_t frameIndex = 0U; frameIndex < database.frames.size(); ++frameIndex) { - const FrameInfo &frame = database.frames[frameIndex]; - std::unique_ptr frameNode (new TreeNode (frame)); + for (std::size_t frameIndex = 0U; frameIndex < database.frames.size(); ++frameIndex) { + const FrameInfo &frame = database.frames[frameIndex]; + std::unique_ptr frameNode(new TreeNode(frame)); - for (std::size_t signalIndex = 0U; signalIndex < frame.signals.size(); ++signalIndex) { - const SignalInfo &signal = frame.signals[signalIndex]; - std::unique_ptr signalNode (new TreeNode (signal)); - frameNode->AddChild (std::move (signalNode)); + for (std::size_t signalIndex = 0U; signalIndex < frame.signals.size(); ++signalIndex) { + const SignalInfo &signal = frame.signals[signalIndex]; + std::unique_ptr signalNode(new TreeNode(signal)); + frameNode->AddChild(std::move(signalNode)); + } + + root->AddChild(std::move(frameNode)); } - root->AddChild (std::move (frameNode)); - } - - return root; + return root; } diff --git a/dbc_tree_builder.h b/dbc_tree_builder.h index 422c94e..2198ff2 100644 --- a/dbc_tree_builder.h +++ b/dbc_tree_builder.h @@ -21,13 +21,13 @@ * @brief Builds a simple tree from parsed DBC database. */ class DbcTreeBuilder { - public: +public: /** * @brief Build tree representation of parsed DBC data. * @param database Parsed database. * @return Root node of the tree. */ - std::unique_ptr Build (const DbcDatabase &database) const; + std::unique_ptr Build(const DbcDatabase &database) const; }; #endif /* DBC_TREE_BUILDER_H */ diff --git a/decode_database.h b/decode_database.h index df46be5..a065940 100644 --- a/decode_database.h +++ b/decode_database.h @@ -12,126 +12,105 @@ #ifndef DECODE_DATABASE_H #define DECODE_DATABASE_H -#include -#include -#include #include +#include +#include +#include /** * @brief Signal byte order used for runtime decoding. */ enum class ByteOrder { - Intel, - Motorola + Intel, + Motorola }; /** * @brief Signal numeric type. */ enum class ValueType { - Unsigned, - Signed + Unsigned, + Signed }; /** * @brief Runtime-ready signal definition. */ struct DecodeSignal { - 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 receivers; /**< Receivers. */ - std::string comment; /**< Comment. */ + 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 receivers; /**< Receivers. */ + 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() + : 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() { + } }; /** * @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 signals; /**< Signal definitions. */ + 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 signals; /**< Signal definitions. */ - DecodeFrame() - : name() - , canId (0U) - , isExtended (false) - , dlc (0U) - , pgn (0U) - , hasPgn (false) - , transmitter() - , comment() - , signals() { - } + DecodeFrame() + : name(), canId(0U), isExtended(false), dlc(0U), pgn(0U), hasPgn(false), transmitter(), comment(), signals() { + } }; /** * @brief Key for fast frame lookup. */ struct FrameKey { - std::uint32_t canId; - bool isExtended; + std::uint32_t canId; + bool isExtended; - FrameKey() - : canId (0U) - , isExtended (false) { - } + FrameKey() + : canId(0U), isExtended(false) { + } - FrameKey (std::uint32_t id, bool extended) - : canId (id) - , isExtended (extended) { - } + FrameKey(std::uint32_t id, bool extended) + : canId(id), isExtended(extended) { + } - bool operator== (const FrameKey &other) const { - return (canId == other.canId) && (isExtended == other.isExtended); - } + bool operator==(const FrameKey &other) const { + return (canId == other.canId) && (isExtended == other.isExtended); + } }; /** * @brief Hasher for frame key. */ struct FrameKeyHasher { - std::size_t operator() (const FrameKey &key) const { - const std::size_t a = static_cast (key.canId); - const std::size_t b = key.isExtended ? 1U : 0U; - return (a * 1315423911U) ^ b; - } + std::size_t operator()(const FrameKey &key) const { + const std::size_t a = static_cast(key.canId); + const std::size_t b = key.isExtended ? 1U : 0U; + return (a * 1315423911U) ^ b; + } }; /** * @brief Runtime decode database with fast lookup by CAN ID. */ struct DecodeDatabase { - std::vector frames; - std::unordered_map frameIndexByKey; + std::vector frames; + std::unordered_map frameIndexByKey; }; #endif /* DECODE_DATABASE_H */ diff --git a/frame_info.h b/frame_info.h index 3463837..ef695f6 100644 --- a/frame_info.h +++ b/frame_info.h @@ -12,9 +12,9 @@ #ifndef FRAME_INFO_H #define FRAME_INFO_H +#include #include #include -#include #include "signal_info.h" @@ -22,27 +22,19 @@ * @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 signals; /**< Signals contained in the frame. */ + 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 signals; /**< Signals contained in the frame. */ - FrameInfo() - : name() - , canId (0U) - , isExtended (false) - , pgn (0U) - , hasPgn (false) - , dlc (0U) - , transmitter() - , comment() - , signals() { - } + FrameInfo() + : name(), canId(0U), isExtended(false), pgn(0U), hasPgn(false), dlc(0U), transmitter(), comment(), signals() { + } }; #endif /* FRAME_INFO_H */ diff --git a/main.cpp b/main.cpp index 6656657..f5e129a 100644 --- a/main.cpp +++ b/main.cpp @@ -9,129 +9,129 @@ * See LICENSE file in the project root for full license text. */ -#include +#include #include +#include #include #include -#include -#include "dbc_parser.h" -#include "dbc_tree_builder.h" #include "dbc_decode_builder.h" #include "dbc_decoder.h" +#include "dbc_parser.h" +#include "dbc_tree_builder.h" -static void PrintTree (const TreeNode *node, int indent) { - if (node == nullptr) - return; +static void PrintTree(const TreeNode *node, int indent) { + if (node == nullptr) + return; - for (int i = 0; i < indent; ++i) - std::cout << " "; + for (int i = 0; i < indent; ++i) + std::cout << " "; - switch (node->GetType()) { - case NodeType::Root: - std::cout << "[root] " << node->GetName() << "\n"; - break; + switch (node->GetType()) { + case NodeType::Root: + std::cout << "[root] " << node->GetName() << "\n"; + break; - case NodeType::Frame: { - const FrameInfo *frame = node->GetFrame(); - std::cout << "[frame] " << node->GetName(); + case NodeType::Frame: { + const FrameInfo *frame = node->GetFrame(); + std::cout << "[frame] " << node->GetName(); - if (frame != nullptr) { - std::cout << " id=0x" << std::hex << frame->canId << std::dec - << " ext=" << (frame->isExtended ? "yes" : "no") - << " dlc=" << static_cast (frame->dlc); + if (frame != nullptr) { + std::cout << " id=0x" << std::hex << frame->canId << std::dec + << " ext=" << (frame->isExtended ? "yes" : "no") + << " dlc=" << static_cast(frame->dlc); - if (frame->hasPgn) - std::cout << " pgn=" << frame->pgn; - } + if (frame->hasPgn) + std::cout << " pgn=" << frame->pgn; + } - std::cout << "\n"; - break; + std::cout << "\n"; + break; + } + + case NodeType::Signal: { + const SignalInfo *signal = node->GetSignal(); + std::cout << "[signal] " << node->GetName(); + + if (signal != nullptr) { + std::cout << " start=" << signal->startBit + << " len=" << signal->length + << " unit=" << signal->unit; + } + + std::cout << "\n"; + break; + } + + default: + std::cout << "[unknown]\n"; + break; } - case NodeType::Signal: { - const SignalInfo *signal = node->GetSignal(); - std::cout << "[signal] " << node->GetName(); + for (std::size_t i = 0U; i < node->GetChildCount(); ++i) + PrintTree(node->GetChild(i), indent + 1); +} - if (signal != nullptr) { - std::cout << " start=" << signal->startBit - << " len=" << signal->length - << " unit=" << signal->unit; - } - - std::cout << "\n"; - break; +static void PrintDecodedFrame(const DecodedFrameValue &decoded) { + if (!decoded.valid || (decoded.definition == nullptr)) { + std::cout << "No frame definition found.\n"; + return; } - default: - std::cout << "[unknown]\n"; - break; - } + std::cout << "Decoded frame: " << decoded.definition->name << "\n"; - for (std::size_t i = 0U; i < node->GetChildCount(); ++i) - PrintTree (node->GetChild (i), indent + 1); + for (std::size_t index = 0U; index < decoded.signals.size(); ++index) { + const DecodedSignalValue &signal = decoded.signals[index]; + + if ((signal.definition == nullptr) || !signal.valid) + continue; + + std::cout << " " << signal.definition->name + << " raw="; + std::visit([](auto rawValue) { std::cout << rawValue; }, signal.rawValue); + std::cout << " physical=" << signal.physicalValue + << " " << signal.definition->unit + << "\n"; + } } -static void PrintDecodedFrame (const DecodedFrameValue &decoded) { - if (!decoded.valid || (decoded.definition == nullptr)) { - std::cout << "No frame definition found.\n"; - return; - } +int main(int argc, char *argv[]) { + if (argc < 2) { + std::cerr << "Usage: dbc_demo \n"; + return 1; + } - std::cout << "Decoded frame: " << decoded.definition->name << "\n"; + try { + DbcParser parser; + DbcDatabase database = parser.ParseFile(argv[1]); - for (std::size_t index = 0U; index < decoded.signals.size(); ++index) { - const DecodedSignalValue &signal = decoded.signals[index]; + DbcTreeBuilder treeBuilder; + std::unique_ptr root = treeBuilder.Build(database); - if ((signal.definition == nullptr) || !signal.valid) - continue; + std::cout << "=== Parsed tree ===\n"; + PrintTree(root.get(), 0); - std::cout << " " << signal.definition->name - << " raw="; - std::visit ([] (auto rawValue) { std::cout << rawValue; }, signal.rawValue); - std::cout << " physical=" << signal.physicalValue - << " " << signal.definition->unit - << "\n"; - } -} + DbcDecodeBuilder decodeBuilder; + DecodeDatabase decodeDatabase = decodeBuilder.Build(database); -int main (int argc, char *argv[]) { - if (argc < 2) { - std::cerr << "Usage: dbc_demo \n"; - return 1; - } - - try { - DbcParser parser; - DbcDatabase database = parser.ParseFile (argv[1]); - - DbcTreeBuilder treeBuilder; - std::unique_ptr root = treeBuilder.Build (database); - - std::cout << "=== Parsed tree ===\n"; - PrintTree (root.get(), 0); - - DbcDecodeBuilder decodeBuilder; - DecodeDatabase decodeDatabase = decodeBuilder.Build (database); - - /* + /* * Example raw frame. * Replace with live CAN frame or trace record later. */ - RawCanFrame rawFrame; - rawFrame.canId = decodeDatabase.frames.empty() ? 0U : decodeDatabase.frames[0].canId; - rawFrame.isExtended = decodeDatabase.frames.empty() ? false : decodeDatabase.frames[0].isExtended; - rawFrame.data.resize (8U, 0U); + RawCanFrame rawFrame; + rawFrame.canId = decodeDatabase.frames.empty() ? 0U : decodeDatabase.frames[0].canId; + rawFrame.isExtended = decodeDatabase.frames.empty() ? false : decodeDatabase.frames[0].isExtended; + rawFrame.data.resize(8U, 0U); - DbcDecoder decoder; - DecodedFrameValue decoded = decoder.Decode (decodeDatabase, rawFrame); + DbcDecoder decoder; + DecodedFrameValue decoded = decoder.Decode(decodeDatabase, rawFrame); - std::cout << "\n=== Decoded frame ===\n"; - PrintDecodedFrame (decoded); - } catch (const std::exception &ex) { - std::cerr << "Error: " << ex.what() << "\n"; - return 2; - } + std::cout << "\n=== Decoded frame ===\n"; + PrintDecodedFrame(decoded); + } catch (const std::exception &ex) { + std::cerr << "Error: " << ex.what() << "\n"; + return 2; + } - return 0; + return 0; } diff --git a/signal_info.h b/signal_info.h index 67a6338..9fa2f34 100644 --- a/signal_info.h +++ b/signal_info.h @@ -12,41 +12,30 @@ #ifndef SIGNAL_INFO_H #define SIGNAL_INFO_H +#include #include #include -#include /** * @brief Describes one signal inside a DBC frame. */ struct SignalInfo { - 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 receivers; /**< Signal receivers. */ - std::string comment; /**< Optional signal comment. */ + 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 receivers; /**< Signal receivers. */ + 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() + : name(), startBit(0U), length(0U), isLittleEndian(true), isSigned(false), factor(1.0), offset(0.0), minimum(0.0), maximum(0.0), unit(), receivers(), comment() { + } }; #endif /* SIGNAL_INFO_H */ diff --git a/tests/dbc_decoder_test.cpp b/tests/dbc_decoder_test.cpp index b16be89..9ac4cd6 100644 --- a/tests/dbc_decoder_test.cpp +++ b/tests/dbc_decoder_test.cpp @@ -5,150 +5,135 @@ #include struct DecodeCase { - const char *name; - ByteOrder byteOrder; - std::uint32_t startBit; - std::uint32_t length; - ValueType valueType; - std::vector data; - bool valid; - std::int64_t rawValue; - double factor; - double offset; - double physicalValue; + const char *name; + ByteOrder byteOrder; + std::uint32_t startBit; + std::uint32_t length; + ValueType valueType; + std::vector data; + bool valid; + std::int64_t rawValue; + double factor; + double offset; + double physicalValue; }; int main() { - const DecodeCase cases[] = { - {"Motorola reproduction", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, - {0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, - {"Motorola within byte", ByteOrder::Motorola, 5U, 4U, ValueType::Unsigned, - {0xAC}, true, 11, 1.0, 0.0, 11.0}, - {"Motorola unaligned crossing", ByteOrder::Motorola, 3U, 12U, ValueType::Unsigned, - {0xAB, 0xCD}, true, 0xBCD, 1.0, 0.0, 3021.0}, - {"Motorola starts at bit zero", ByteOrder::Motorola, 0U, 2U, ValueType::Unsigned, - {0x01, 0x80}, true, 3, 1.0, 0.0, 3.0}, - {"Motorola second byte", ByteOrder::Motorola, 15U, 16U, ValueType::Unsigned, - {0xFF, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, - {"Motorola signed scaled", ByteOrder::Motorola, 7U, 16U, ValueType::Signed, - {0xFF, 0xFE}, true, -2, 0.5, 10.0, 9.0}, - {"Motorola 64 bits", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, - {0, 0, 0, 0, 0, 0, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, - {"Motorola 64 bits high bit", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, - {0x40, 0, 0, 0, 0, 0, 0, 0}, true, 0x4000000000000000LL, - 1.0, 0.0, 4611686018427387904.0}, - {"Motorola short payload", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, - {0x12}, false, 0, 1.0, 0.0, 0.0}, - {"Motorola empty payload", ByteOrder::Motorola, 7U, 8U, ValueType::Unsigned, - {}, false, 0, 1.0, 0.0, 0.0}, - {"Motorola large start", ByteOrder::Motorola, - std::numeric_limits::max(), 8U, ValueType::Unsigned, - {0xFF}, false, 0, 1.0, 0.0, 0.0}, - {"Motorola zero length", ByteOrder::Motorola, 7U, 0U, ValueType::Unsigned, - {0xFF}, false, 0, 1.0, 0.0, 0.0}, - {"Motorola excessive length", ByteOrder::Motorola, 7U, 65U, ValueType::Unsigned, - std::vector (9U, 0xFF), false, 0, 1.0, 0.0, 0.0}, - {"Intel regression", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, - {0x12, 0x34}, true, 0x3412, 1.0, 0.0, 13330.0}, - {"Intel signed regression", ByteOrder::Intel, 0U, 16U, ValueType::Signed, - {0xFE, 0xFF}, true, -2, 0.5, 10.0, 9.0}, - {"Intel short payload", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, - {0x12}, false, 0, 1.0, 0.0, 0.0} - }; + const DecodeCase cases[] = { + {"Motorola reproduction", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, + {"Motorola within byte", ByteOrder::Motorola, 5U, 4U, ValueType::Unsigned, {0xAC}, true, 11, 1.0, 0.0, 11.0}, + {"Motorola unaligned crossing", ByteOrder::Motorola, 3U, 12U, ValueType::Unsigned, {0xAB, 0xCD}, true, 0xBCD, 1.0, 0.0, 3021.0}, + {"Motorola starts at bit zero", ByteOrder::Motorola, 0U, 2U, ValueType::Unsigned, {0x01, 0x80}, true, 3, 1.0, 0.0, 3.0}, + {"Motorola second byte", ByteOrder::Motorola, 15U, 16U, ValueType::Unsigned, {0xFF, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, + {"Motorola signed scaled", ByteOrder::Motorola, 7U, 16U, ValueType::Signed, {0xFF, 0xFE}, true, -2, 0.5, 10.0, 9.0}, + {"Motorola 64 bits", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, {0, 0, 0, 0, 0, 0, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, + {"Motorola 64 bits high bit", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, {0x40, 0, 0, 0, 0, 0, 0, 0}, true, 0x4000000000000000LL, 1.0, 0.0, 4611686018427387904.0}, + {"Motorola short payload", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12}, false, 0, 1.0, 0.0, 0.0}, + {"Motorola empty payload", ByteOrder::Motorola, 7U, 8U, ValueType::Unsigned, {}, false, 0, 1.0, 0.0, 0.0}, + {"Motorola large start", ByteOrder::Motorola, std::numeric_limits::max(), 8U, ValueType::Unsigned, {0xFF}, false, 0, 1.0, 0.0, 0.0}, + {"Motorola zero length", ByteOrder::Motorola, 7U, 0U, ValueType::Unsigned, {0xFF}, false, 0, 1.0, 0.0, 0.0}, + {"Motorola excessive length", ByteOrder::Motorola, 7U, 65U, ValueType::Unsigned, + std::vector(9U, 0xFF), false, 0, 1.0, 0.0, 0.0}, + {"Intel regression", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12, 0x34}, true, 0x3412, 1.0, 0.0, 13330.0}, + {"Intel signed regression", ByteOrder::Intel, 0U, 16U, ValueType::Signed, {0xFE, 0xFF}, true, -2, 0.5, 10.0, 9.0}, + {"Intel short payload", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12}, false, 0, 1.0, 0.0, 0.0}}; - int failures = 0; - for (const DecodeCase &test : cases) { - DecodeSignal signal; - signal.name = test.name; - signal.byteOrder = test.byteOrder; - signal.startBit = test.startBit; - signal.length = test.length; - signal.valueType = test.valueType; - signal.factor = test.factor; - signal.offset = test.offset; - - DecodeFrame definition; - definition.canId = 0x123U; - definition.dlc = static_cast (test.data.size()); - definition.signals.push_back (signal); - DecodeDatabase database; - database.frames.push_back (definition); - database.frameIndexByKey.emplace (FrameKey (definition.canId, false), 0U); - - RawCanFrame frame; - frame.canId = definition.canId; - frame.data = test.data; - const DecodedFrameValue result = DbcDecoder().Decode (database, frame); - const bool passed = result.valid && - (result.definition == &database.frames[0]) && - (result.signals.size() == 1U) && - (result.signals[0].definition == &database.frames[0].signals[0]) && - (result.signals[0].valid == test.valid) && - (!test.valid || (((test.valueType == ValueType::Signed) - ? (std::get_if (&result.signals[0].rawValue) && - std::get (result.signals[0].rawValue) == test.rawValue) - : (std::get_if (&result.signals[0].rawValue) && - std::get (result.signals[0].rawValue) == - static_cast (test.rawValue))) && - (result.signals[0].physicalValue == test.physicalValue))); - if (!passed) { - std::cerr << "FAIL: " << test.name << '\n'; - ++failures; - } - } - std::size_t boundaryCases = 0U; - for (ByteOrder order : {ByteOrder::Intel, ByteOrder::Motorola}) { - for (ValueType type : {ValueType::Unsigned, ValueType::Signed}) { - for (std::uint64_t bits : {std::uint64_t (0U), std::uint64_t (0x7FFFFFFFFFFFFFFFULL), - std::uint64_t (0x8000000000000000ULL), - std::uint64_t (0x8000000000000001ULL), - std::uint64_t (0xFFFFFFFFFFFFFFFFULL)}) { - DecodeDatabase database; - DecodeFrame definition; + int failures = 0; + for (const DecodeCase &test: cases) { DecodeSignal signal; - signal.startBit = order == ByteOrder::Intel ? 0U : 7U; - signal.length = 64U; - signal.byteOrder = order; - signal.valueType = type; - signal.factor = 0.5; - signal.offset = 10.0; - definition.signals.push_back (signal); - database.frames.push_back (definition); - database.frameIndexByKey.emplace (FrameKey (0U, false), 0U); + signal.name = test.name; + signal.byteOrder = test.byteOrder; + signal.startBit = test.startBit; + signal.length = test.length; + signal.valueType = test.valueType; + signal.factor = test.factor; + signal.offset = test.offset; + + DecodeFrame definition; + definition.canId = 0x123U; + definition.dlc = static_cast(test.data.size()); + definition.signals.push_back(signal); + DecodeDatabase database; + database.frames.push_back(definition); + database.frameIndexByKey.emplace(FrameKey(definition.canId, false), 0U); + RawCanFrame frame; - for (unsigned byte = 0U; byte < 8U; ++byte) { - const unsigned shift = (order == ByteOrder::Intel ? byte : 7U - byte) * 8U; - frame.data.push_back (static_cast (bits >> shift)); + frame.canId = definition.canId; + frame.data = test.data; + const DecodedFrameValue result = DbcDecoder().Decode(database, frame); + const bool passed = result.valid && + (result.definition == &database.frames[0]) && + (result.signals.size() == 1U) && + (result.signals[0].definition == &database.frames[0].signals[0]) && + (result.signals[0].valid == test.valid) && + (!test.valid || (((test.valueType == ValueType::Signed) + ? (std::get_if(&result.signals[0].rawValue) && + std::get(result.signals[0].rawValue) == test.rawValue) + : (std::get_if(&result.signals[0].rawValue) && + std::get(result.signals[0].rawValue) == + static_cast(test.rawValue))) && + (result.signals[0].physicalValue == test.physicalValue))); + if (!passed) { + std::cerr << "FAIL: " << test.name << '\n'; + ++failures; } - const auto result = DbcDecoder().Decode (database, frame); - const std::int64_t signedExpected = bits <= 0x7FFFFFFFFFFFFFFFULL - ? static_cast (bits) - : std::numeric_limits::min() + - static_cast (bits - 0x8000000000000000ULL); - const auto &decoded = result.signals.at (0U); - const auto expected = type == ValueType::Unsigned - ? std::variant (bits) - : std::variant (signedExpected); - const double physical = (type == ValueType::Unsigned - ? static_cast (bits) : static_cast (signedExpected)) * 0.5 + 10.0; - std::ostringstream actualText; - std::ostringstream expectedText; - std::visit ([&actualText] (auto raw) { actualText << raw; }, decoded.rawValue); - if (type == ValueType::Unsigned) - expectedText << bits; - else - expectedText << signedExpected; - if (!decoded.valid || decoded.rawValue != expected || - decoded.physicalValue != physical || actualText.str() != expectedText.str()) { - std::cerr << "FAIL: 64-bit boundary " << bits << '\n'; - ++failures; - } - ++boundaryCases; - } } - } - if (failures != 0) - return 1; - std::cout << "All " << sizeof (cases) / sizeof (cases[0]) + boundaryCases << " decoder cases passed.\n"; - return 0; + std::size_t boundaryCases = 0U; + for (ByteOrder order: {ByteOrder::Intel, ByteOrder::Motorola}) { + for (ValueType type: {ValueType::Unsigned, ValueType::Signed}) { + for (std::uint64_t bits: {std::uint64_t(0U), std::uint64_t(0x7FFFFFFFFFFFFFFFULL), + std::uint64_t(0x8000000000000000ULL), + std::uint64_t(0x8000000000000001ULL), + std::uint64_t(0xFFFFFFFFFFFFFFFFULL)}) { + DecodeDatabase database; + DecodeFrame definition; + DecodeSignal signal; + signal.startBit = order == ByteOrder::Intel ? 0U : 7U; + signal.length = 64U; + signal.byteOrder = order; + signal.valueType = type; + signal.factor = 0.5; + signal.offset = 10.0; + definition.signals.push_back(signal); + database.frames.push_back(definition); + database.frameIndexByKey.emplace(FrameKey(0U, false), 0U); + RawCanFrame frame; + for (unsigned byte = 0U; byte < 8U; ++byte) { + const unsigned shift = (order == ByteOrder::Intel ? byte : 7U - byte) * 8U; + frame.data.push_back(static_cast(bits >> shift)); + } + const auto result = DbcDecoder().Decode(database, frame); + const std::int64_t signedExpected = bits <= 0x7FFFFFFFFFFFFFFFULL + ? static_cast(bits) + : std::numeric_limits::min() + + static_cast(bits - 0x8000000000000000ULL); + const auto &decoded = result.signals.at(0U); + const auto expected = type == ValueType::Unsigned + ? std::variant(bits) + : std::variant(signedExpected); + const double physical = (type == ValueType::Unsigned + ? static_cast(bits) + : static_cast(signedExpected)) * + 0.5 + + 10.0; + std::ostringstream actualText; + std::ostringstream expectedText; + std::visit([&actualText](auto raw) { actualText << raw; }, decoded.rawValue); + if (type == ValueType::Unsigned) + expectedText << bits; + else + expectedText << signedExpected; + if (!decoded.valid || decoded.rawValue != expected || + decoded.physicalValue != physical || actualText.str() != expectedText.str()) { + std::cerr << "FAIL: 64-bit boundary " << bits << '\n'; + ++failures; + } + ++boundaryCases; + } + } + } + if (failures != 0) + return 1; + std::cout << "All " << sizeof(cases) / sizeof(cases[0]) + boundaryCases << " decoder cases passed.\n"; + return 0; } diff --git a/tests/dbc_parser_test.cpp b/tests/dbc_parser_test.cpp index b27f9a1..c0a54ca 100644 --- a/tests/dbc_parser_test.cpp +++ b/tests/dbc_parser_test.cpp @@ -8,223 +8,246 @@ #include struct Fixture { - std::filesystem::path path = std::filesystem::temp_directory_path() / - ("dbc_parser_test_" + std::to_string ( - std::chrono::steady_clock::now().time_since_epoch().count()) + ".dbc"); - ~Fixture() { std::error_code error; std::filesystem::remove (path, error); } - void Write (const std::string &text) const { - std::ofstream output (path); - output << text; - if (!output) - throw std::runtime_error ("Cannot write test fixture."); - } + std::filesystem::path path = std::filesystem::temp_directory_path() / + ("dbc_parser_test_" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + ".dbc"); + ~Fixture() { + std::error_code error; + std::filesystem::remove(path, error); + } + void Write(const std::string &text) const { + std::ofstream output(path); + output << text; + if (!output) + throw std::runtime_error("Cannot write test fixture."); + } }; class CountingHandler : public DbcStatementHandler { - public: +public: inline static int instances = 0; inline static int calls = 0; CountingHandler() { ++instances; } - void Handle (const std::string &, DbcParseContext &context) const override { - ++calls; - context.database.frames.emplace_back(); + void Handle(const std::string &, DbcParseContext &context) const override { + ++calls; + context.database.frames.emplace_back(); } }; int main() { - Fixture fixture; - int failures = 0; - std::size_t count = 0U; - const auto check = [&] (bool passed, const std::string &name) { - ++count; - if (!passed) { ++failures; std::cerr << "FAIL: " << name << '\n'; } - }; - struct ValidCase { const char *line; std::uint32_t id; bool extended; unsigned length; }; - const ValidCase valid[] = { - {"BO_ 0 Frame: 0 ECU", 0U, false, 0U}, - {"BO_ 2047 Frame: 8 ECU", 2047U, false, 8U}, - {"BO_ 2048 Frame: 64 ECU", 2048U, true, 64U}, - {"BO_ 536870911 Frame: 255 ECU", 0x1FFFFFFFU, true, 255U}, - {"BO_ 2147483649 Frame: 8 ECU", 1U, true, 8U}, - {"BO_ 2684354559 Frame: 8 ECU", 0x1FFFFFFFU, true, 8U}, - {" BO_\t256\tFrame :\t8\tECU \r", 256U, false, 8U} - }; - for (const auto &test : valid) { - fixture.Write (std::string (test.line) + '\n'); - try { - const auto database = DbcParser().ParseFile (fixture.path.string()); - check (database.frames.size() == 1U && database.frames[0].name == "Frame" && - database.frames[0].canId == test.id && - database.frames[0].isExtended == test.extended && - database.frames[0].dlc == test.length && - database.frames[0].transmitter == "ECU", test.line); - } catch (const std::exception &error) { check (false, error.what()); } - } - const char *invalid[] = { - "BO_ invalid", "BO_", "BO_ 1", "BO_ 1 : 8 ECU", "BO_ 1 Frame 8 ECU", - "BO_ 1 Frame:", "BO_ 1 Frame: 8", "BO_ 1 Frame: 8 ECU extra", - "BO_ 1 Two Names: 8 ECU", "BO_ -1 Frame: 8 ECU", "BO_ +1 Frame: 8 ECU", - "BO_ 1x Frame: 8 ECU", "BO_ 0x123 Frame: 8 ECU", "BO_ 1.5 Frame: 8 ECU", - "BO_ 4294967296 Frame: 8 ECU", "BO_ 999999999999999999999 Frame: 8 ECU", - "BO_ 536870912 Frame: 8 ECU", "BO_ 1073741824 Frame: 8 ECU", - "BO_ 2684354560 Frame: 8 ECU", "BO_ 4294967295 Frame: 8 ECU", - "BO_ 1 Frame: -1 ECU", "BO_ 1 Frame: +8 ECU", "BO_ 1 Frame: 8x ECU", - "BO_ 1 Frame: 8.5 ECU", "BO_ 1 Frame: 256 ECU", - "BO_ 1 Frame: 4294967296 ECU", "BO_\tinvalid" - }; - for (const auto *line : invalid) { - fixture.Write (std::string ("VERSION \"test\"\n\n") + line + '\n'); - try { - DbcParser().ParseFile (fixture.path.string()); - check (false, line); - } catch (const std::runtime_error &error) { - const std::string prefix = fixture.path.string() + ":3: "; - check (std::string (error.what()).find (prefix) == 0U && - std::string (error.what()).size() > prefix.size(), line); + Fixture fixture; + int failures = 0; + std::size_t count = 0U; + const auto check = [&](bool passed, const std::string &name) { + ++count; + if (!passed) { + ++failures; + std::cerr << "FAIL: " << name << '\n'; + } + }; + struct ValidCase { + const char *line; + std::uint32_t id; + bool extended; + unsigned length; + }; + const ValidCase valid[] = { + {"BO_ 0 Frame: 0 ECU", 0U, false, 0U}, + {"BO_ 2047 Frame: 8 ECU", 2047U, false, 8U}, + {"BO_ 2048 Frame: 64 ECU", 2048U, true, 64U}, + {"BO_ 536870911 Frame: 255 ECU", 0x1FFFFFFFU, true, 255U}, + {"BO_ 2147483649 Frame: 8 ECU", 1U, true, 8U}, + {"BO_ 2684354559 Frame: 8 ECU", 0x1FFFFFFFU, true, 8U}, + {" BO_\t256\tFrame :\t8\tECU \r", 256U, false, 8U}}; + for (const auto &test: valid) { + fixture.Write(std::string(test.line) + '\n'); + try { + const auto database = DbcParser().ParseFile(fixture.path.string()); + check(database.frames.size() == 1U && database.frames[0].name == "Frame" && + database.frames[0].canId == test.id && + database.frames[0].isExtended == test.extended && + database.frames[0].dlc == test.length && + database.frames[0].transmitter == "ECU", + test.line); + } catch (const std::exception &error) { check(false, error.what()); } } - } - fixture.Write ( - "BO_TX_BU_ 256 : ECU;\nBO_ 256 Frame: 8 ECU\n" - " SG_ Speed : 0|16@1+ (0.5,1) [0|100] \"rpm\" ECU\n" - "CM_ BO_ 256 \"Frame comment\";\nCM_ SG_ 256 Speed \"Signal comment\";\n" - "BO_ 257 Second: 8 ECU\n"); - const auto database = DbcParser().ParseFile (fixture.path.string()); - check (database.frames.size() == 2U && database.frames[0].signals.size() == 1U && - database.frames[0].comment == "Frame comment" && - database.frames[0].signals[0].comment == "Signal comment", "Integration"); - fixture.Write ("\nSG_ Speed : invalid\n"); - try { - DbcParser().ParseFile (fixture.path.string()); - check (false, "Signal error location"); - } catch (const std::runtime_error &error) { - check (std::string (error.what()).find (fixture.path.string() + ":2: ") == 0U, - "Signal error location"); - } - const DbcParser signalParser; - const auto signalLine = [] (const std::string &start, const std::string &length, + const char *invalid[] = { + "BO_ invalid", "BO_", "BO_ 1", "BO_ 1 : 8 ECU", "BO_ 1 Frame 8 ECU", + "BO_ 1 Frame:", "BO_ 1 Frame: 8", "BO_ 1 Frame: 8 ECU extra", + "BO_ 1 Two Names: 8 ECU", "BO_ -1 Frame: 8 ECU", "BO_ +1 Frame: 8 ECU", + "BO_ 1x Frame: 8 ECU", "BO_ 0x123 Frame: 8 ECU", "BO_ 1.5 Frame: 8 ECU", + "BO_ 4294967296 Frame: 8 ECU", "BO_ 999999999999999999999 Frame: 8 ECU", + "BO_ 536870912 Frame: 8 ECU", "BO_ 1073741824 Frame: 8 ECU", + "BO_ 2684354560 Frame: 8 ECU", "BO_ 4294967295 Frame: 8 ECU", + "BO_ 1 Frame: -1 ECU", "BO_ 1 Frame: +8 ECU", "BO_ 1 Frame: 8x ECU", + "BO_ 1 Frame: 8.5 ECU", "BO_ 1 Frame: 256 ECU", + "BO_ 1 Frame: 4294967296 ECU", "BO_\tinvalid"}; + for (const auto *line: invalid) { + fixture.Write(std::string("VERSION \"test\"\n\n") + line + '\n'); + try { + DbcParser().ParseFile(fixture.path.string()); + check(false, line); + } catch (const std::runtime_error &error) { + const std::string prefix = fixture.path.string() + ":3: "; + check(std::string(error.what()).find(prefix) == 0U && + std::string(error.what()).size() > prefix.size(), + line); + } + } + fixture.Write( + "BO_TX_BU_ 256 : ECU;\nBO_ 256 Frame: 8 ECU\n" + " SG_ Speed : 0|16@1+ (0.5,1) [0|100] \"rpm\" ECU\n" + "CM_ BO_ 256 \"Frame comment\";\nCM_ SG_ 256 Speed \"Signal comment\";\n" + "BO_ 257 Second: 8 ECU\n"); + const auto database = DbcParser().ParseFile(fixture.path.string()); + check(database.frames.size() == 2U && database.frames[0].signals.size() == 1U && + database.frames[0].comment == "Frame comment" && + database.frames[0].signals[0].comment == "Signal comment", + "Integration"); + fixture.Write("\nSG_ Speed : invalid\n"); + try { + DbcParser().ParseFile(fixture.path.string()); + check(false, "Signal error location"); + } catch (const std::runtime_error &error) { + check(std::string(error.what()).find(fixture.path.string() + ":2: ") == 0U, + "Signal error location"); + } + const DbcParser signalParser; + const auto signalLine = [](const std::string &start, const std::string &length, const std::string &order, const std::string &factor, const std::string &offset, const std::string &minimum, const std::string &maximum) { - return "SG_ Value : " + start + "|" + length + "@" + order + - " (" + factor + "," + offset + ") [" + minimum + "|" + maximum + "] \"\" ECU"; - }; - const auto rejectSignal = [&] (const std::string &line, unsigned payload = 8U) { - fixture.Write ("BO_ 1 Frame: " + std::to_string (payload) + " ECU\n\n" + line + "\n"); - try { - signalParser.ParseFile (fixture.path.string()); - check (false, "Reject " + line); - } catch (const std::runtime_error &error) { - const std::string prefix = fixture.path.string() + ":3: "; - check (std::string (error.what()).find (prefix) == 0U && - std::string (error.what()).size() > prefix.size(), "Reject " + line); + return "SG_ Value : " + start + "|" + length + "@" + order + + " (" + factor + "," + offset + ") [" + minimum + "|" + maximum + "] \"\" ECU"; + }; + const auto rejectSignal = [&](const std::string &line, unsigned payload = 8U) { + fixture.Write("BO_ 1 Frame: " + std::to_string(payload) + " ECU\n\n" + line + "\n"); + try { + signalParser.ParseFile(fixture.path.string()); + check(false, "Reject " + line); + } catch (const std::runtime_error &error) { + const std::string prefix = fixture.path.string() + ":3: "; + check(std::string(error.what()).find(prefix) == 0U && + std::string(error.what()).size() > prefix.size(), + "Reject " + line); + } + }; + const std::string ordinary = signalLine("0", "8", "1+", "1", "0", "0", "255"); + for (const std::string value: {"-1", "+1", "0junk", "0x10", "1.5", + "4294967296", "999999999999999999999"}) { + rejectSignal(signalLine(value, "8", "1+", "1", "0", "0", "255")); + rejectSignal(signalLine("0", value, "1+", "1", "0", "0", "255")); } - }; - const std::string ordinary = signalLine ("0", "8", "1+", "1", "0", "0", "255"); - for (const std::string value : {"-1", "+1", "0junk", "0x10", "1.5", - "4294967296", "999999999999999999999"}) { - rejectSignal (signalLine (value, "8", "1+", "1", "0", "0", "255")); - rejectSignal (signalLine ("0", value, "1+", "1", "0", "0", "255")); - } - for (const std::string length : {"0", "65"}) - rejectSignal (signalLine ("0", length, "1+", "1", "0", "0", "255")); - for (const std::string order : {"2+", "9-", "1", "1x", "1++", "01+"}) - rejectSignal (signalLine ("0", "8", order, "1", "0", "0", "255")); - for (const std::string value : {"1junk", "nan", "NaN", "inf", "-inf", "1e999", "1e-999", "0x1p2", "", "1e", "1.2.3"}) { - rejectSignal (signalLine ("0", "8", "1+", value, "0", "0", "255")); - rejectSignal (signalLine ("0", "8", "1+", "1", value, "0", "255")); - rejectSignal (signalLine ("0", "8", "1+", "1", "0", value, "255")); - rejectSignal (signalLine ("0", "8", "1+", "1", "0", "0", value)); - } - rejectSignal (signalLine ("0", "8", "1+", "1", "0", "2", "1")); - for (const std::string name : {"", "Two Names", "Value M", "Value m1", "Value m1M"}) { - std::string line = ordinary; - line.replace (4U, 5U, name); - rejectSignal (line); - } - for (const std::string broken : { - "SG_", "SG_ Value", "SG_ Value : 0|8@1+ (1,0) [0|255] ECU", - "SG_ Value : 0|8@1+ (1,0) [0|255] \"\"", - "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU,", - "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU extra"}) - rejectSignal (broken); - rejectSignal (signalLine ("64", "1", "1+", "1", "0", "0", "1")); - rejectSignal (signalLine ("63", "2", "1+", "1", "0", "0", "3")); - rejectSignal (signalLine ("56", "2", "0+", "1", "0", "0", "3")); - rejectSignal (signalLine ("4294967295", "64", "1+", "1", "0", "0", "1")); - rejectSignal (ordinary, 0U); - for (const char delimiter : {'|', '@', '(', ')', '[', ']', '"'}) { - std::string line = ordinary; - line.erase (line.find (delimiter), 1U); - rejectSignal (line); - } - fixture.Write ("BO_ 1 Frame: 8 ECU\n" + - signalLine ("0", "8", "1+", "0", "0", "0", "0") + "\n" + - signalLine ("8", "8", "1-", "-1", "0", "-255", "0") + "\n"); - const auto factors = signalParser.ParseFile (fixture.path.string()); - check (factors.frames[0].signals.size() == 2U && - factors.frames[0].signals[0].factor == 0.0 && - factors.frames[0].signals[1].factor == -1.0, - "Zero and negative factors and equal range boundaries"); + for (const std::string length: {"0", "65"}) + rejectSignal(signalLine("0", length, "1+", "1", "0", "0", "255")); + for (const std::string order: {"2+", "9-", "1", "1x", "1++", "01+"}) + rejectSignal(signalLine("0", "8", order, "1", "0", "0", "255")); + for (const std::string value: {"1junk", "nan", "NaN", "inf", "-inf", "1e999", "1e-999", "0x1p2", "", "1e", "1.2.3"}) { + rejectSignal(signalLine("0", "8", "1+", value, "0", "0", "255")); + rejectSignal(signalLine("0", "8", "1+", "1", value, "0", "255")); + rejectSignal(signalLine("0", "8", "1+", "1", "0", value, "255")); + rejectSignal(signalLine("0", "8", "1+", "1", "0", "0", value)); + } + rejectSignal(signalLine("0", "8", "1+", "1", "0", "2", "1")); + for (const std::string name: {"", "Two Names", "Value M", "Value m1", "Value m1M"}) { + std::string line = ordinary; + line.replace(4U, 5U, name); + rejectSignal(line); + } + for (const std::string broken: { + "SG_", "SG_ Value", "SG_ Value : 0|8@1+ (1,0) [0|255] ECU", + "SG_ Value : 0|8@1+ (1,0) [0|255] \"\"", + "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU,", + "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU extra"}) + rejectSignal(broken); + rejectSignal(signalLine("64", "1", "1+", "1", "0", "0", "1")); + rejectSignal(signalLine("63", "2", "1+", "1", "0", "0", "3")); + rejectSignal(signalLine("56", "2", "0+", "1", "0", "0", "3")); + rejectSignal(signalLine("4294967295", "64", "1+", "1", "0", "0", "1")); + rejectSignal(ordinary, 0U); + for (const char delimiter: {'|', '@', '(', ')', '[', ']', '"'}) { + std::string line = ordinary; + line.erase(line.find(delimiter), 1U); + rejectSignal(line); + } + fixture.Write("BO_ 1 Frame: 8 ECU\n" + + signalLine("0", "8", "1+", "0", "0", "0", "0") + "\n" + + signalLine("8", "8", "1-", "-1", "0", "-255", "0") + "\n"); + const auto factors = signalParser.ParseFile(fixture.path.string()); + check(factors.frames[0].signals.size() == 2U && + factors.frames[0].signals[0].factor == 0.0 && + factors.frames[0].signals[1].factor == -1.0, + "Zero and negative factors and equal range boundaries"); - struct SignalCase { const char *start; const char *length; const char *order; unsigned payload; }; - const SignalCase validSignals[] = { - {"0", "1", "1+", 1U}, {"7", "1", "0-", 1U}, - {"0", "64", "1+", 8U}, {"7", "64", "0-", 8U}, - {"63", "1", "1+", 8U}, {"56", "1", "0+", 8U}, - {"3", "12", "0+", 2U}, {"2039", "1", "1+", 255U} - }; - for (const auto &test : validSignals) { - fixture.Write ("BO_ 1 Frame: " + std::to_string (test.payload) + " ECU\n" + - signalLine (test.start, test.length, test.order, ".5e+1", "-2.5E-1", "-1.", "+2e2") + "\n"); + struct SignalCase { + const char *start; + const char *length; + const char *order; + unsigned payload; + }; + const SignalCase validSignals[] = { + {"0", "1", "1+", 1U}, + {"7", "1", "0-", 1U}, + {"0", "64", "1+", 8U}, + {"7", "64", "0-", 8U}, + {"63", "1", "1+", 8U}, + {"56", "1", "0+", 8U}, + {"3", "12", "0+", 2U}, + {"2039", "1", "1+", 255U}}; + for (const auto &test: validSignals) { + fixture.Write("BO_ 1 Frame: " + std::to_string(test.payload) + " ECU\n" + + signalLine(test.start, test.length, test.order, ".5e+1", "-2.5E-1", "-1.", "+2e2") + "\n"); + try { + const auto parsed = signalParser.ParseFile(fixture.path.string()); + const auto &signal = parsed.frames.at(0).signals.at(0); + check(signal.startBit == std::stoul(test.start) && + signal.length == std::stoul(test.length) && + signal.isLittleEndian == (test.order[0] == '1') && + signal.isSigned == (test.order[1] == '-') && + signal.factor == 5.0 && signal.offset == -0.25 && + signal.minimum == -1.0 && signal.maximum == 200.0, + "Valid signal boundary and numeric metadata"); + } catch (const std::exception &error) { check(false, error.what()); } + } + fixture.Write("BO_ 1 Frame: 8 ECU\n" + "SG_\tValue\t:\t0 | 8 @1+ ( 1 , 0 ) [ 0 | 255 ] \"rpm\" ECU1,\tECU2\n"); try { - const auto parsed = signalParser.ParseFile (fixture.path.string()); - const auto &signal = parsed.frames.at (0).signals.at (0); - check (signal.startBit == std::stoul (test.start) && - signal.length == std::stoul (test.length) && - signal.isLittleEndian == (test.order[0] == '1') && - signal.isSigned == (test.order[1] == '-') && - signal.factor == 5.0 && signal.offset == -0.25 && - signal.minimum == -1.0 && signal.maximum == 200.0, - "Valid signal boundary and numeric metadata"); - } catch (const std::exception &error) { check (false, error.what()); } - } - fixture.Write ("BO_ 1 Frame: 8 ECU\n" - "SG_\tValue\t:\t0 | 8 @1+ ( 1 , 0 ) [ 0 | 255 ] \"rpm\" ECU1,\tECU2\n"); - try { - const auto parsed = signalParser.ParseFile (fixture.path.string()); - const auto &signal = parsed.frames.at (0).signals.at (0); - check (signal.name == "Value" && signal.unit == "rpm" && - signal.receivers == std::vector ({"ECU1", "ECU2"}), - "Signal tabs, spaces, and receiver list"); - } catch (const std::exception &error) { check (false, error.what()); } - DbcDatabase dispatchDatabase; - DbcParseContext context {dispatchDatabase, nullptr}; - DbcStatementDispatcher dispatcher; - dispatcher.RegisterType ("TEST_"); - check (dispatcher.Dispatch ("TEST_ first", context) && - dispatcher.Dispatch ("TEST_ second", context) && - CountingHandler::instances == 1 && CountingHandler::calls == 2 && - dispatchDatabase.frames.size() == 2U, "Factory dispatch and handler reuse"); - check (!dispatcher.Dispatch ("TEST_OTHER data", context) && - !dispatcher.Dispatch ("BO_TX_BU_ 1 : ECU;", context) && - !dispatcher.Dispatch ("VAL_ 1 Speed 0 \"Stopped\";", context) && - CountingHandler::calls == 2, "Exact and unknown keyword dispatch"); - const DbcParser parser; - fixture.Write ("BO_ 1 First: 8 ECU\n"); - check (parser.ParseFile (fixture.path.string()).frames.size() == 1U, "First parse"); - fixture.Write ("SG_ Speed : invalid\n"); - try { - parser.ParseFile (fixture.path.string()); - check (false, "Independent parse context"); - } catch (const std::runtime_error &error) { - check (std::string (error.what()).find ("Signal found before any frame") != - std::string::npos, "Independent parse context"); - } - fixture.Write ("BO_ 2 Second: 8 ECU\n"); - const auto recovered = parser.ParseFile (fixture.path.string()); - check (recovered.frames.size() == 1U && recovered.frames[0].canId == 2U, - "Fresh parse after error"); - if (failures != 0) return 1; - std::cout << "All " << count << " parser cases passed.\n"; - return 0; + const auto parsed = signalParser.ParseFile(fixture.path.string()); + const auto &signal = parsed.frames.at(0).signals.at(0); + check(signal.name == "Value" && signal.unit == "rpm" && + signal.receivers == std::vector({"ECU1", "ECU2"}), + "Signal tabs, spaces, and receiver list"); + } catch (const std::exception &error) { check(false, error.what()); } + DbcDatabase dispatchDatabase; + DbcParseContext context{dispatchDatabase, nullptr}; + DbcStatementDispatcher dispatcher; + dispatcher.RegisterType("TEST_"); + check(dispatcher.Dispatch("TEST_ first", context) && + dispatcher.Dispatch("TEST_ second", context) && + CountingHandler::instances == 1 && CountingHandler::calls == 2 && + dispatchDatabase.frames.size() == 2U, + "Factory dispatch and handler reuse"); + check(!dispatcher.Dispatch("TEST_OTHER data", context) && + !dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) && + !dispatcher.Dispatch("VAL_ 1 Speed 0 \"Stopped\";", context) && + CountingHandler::calls == 2, + "Exact and unknown keyword dispatch"); + const DbcParser parser; + fixture.Write("BO_ 1 First: 8 ECU\n"); + check(parser.ParseFile(fixture.path.string()).frames.size() == 1U, "First parse"); + fixture.Write("SG_ Speed : invalid\n"); + try { + parser.ParseFile(fixture.path.string()); + check(false, "Independent parse context"); + } catch (const std::runtime_error &error) { + check(std::string(error.what()).find("Signal found before any frame") != + std::string::npos, + "Independent parse context"); + } + fixture.Write("BO_ 2 Second: 8 ECU\n"); + const auto recovered = parser.ParseFile(fixture.path.string()); + check(recovered.frames.size() == 1U && recovered.frames[0].canId == 2U, + "Fresh parse after error"); + if (failures != 0) return 1; + std::cout << "All " << count << " parser cases passed.\n"; + return 0; } diff --git a/tree_node.cpp b/tree_node.cpp index 4bb3b48..e8af979 100644 --- a/tree_node.cpp +++ b/tree_node.cpp @@ -12,64 +12,52 @@ #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"), m_children(), m_frame(), m_signal() { } -TreeNode::TreeNode (const FrameInfo &frame) - : m_type (NodeType::Frame) - , m_name (frame.name) - , m_children() - , m_frame (new FrameInfo (frame)) - , m_signal() { +TreeNode::TreeNode(const FrameInfo &frame) + : m_type(NodeType::Frame), m_name(frame.name), m_children(), m_frame(new FrameInfo(frame)), m_signal() { } -TreeNode::TreeNode (const SignalInfo &signal) - : m_type (NodeType::Signal) - , m_name (signal.name) - , m_children() - , m_frame() - , m_signal (new SignalInfo (signal)) { +TreeNode::TreeNode(const SignalInfo &signal) + : m_type(NodeType::Signal), m_name(signal.name), m_children(), m_frame(), m_signal(new SignalInfo(signal)) { } -void TreeNode::AddChild (std::unique_ptr child) { - if (child) - m_children.push_back (std::move (child)); +void TreeNode::AddChild(std::unique_ptr child) { + if (child) + m_children.push_back(std::move(child)); } std::size_t TreeNode::GetChildCount() const { - return m_children.size(); + return m_children.size(); } -const TreeNode *TreeNode::GetChild (std::size_t index) const { - if (index >= m_children.size()) - return nullptr; +const TreeNode *TreeNode::GetChild(std::size_t index) const { + if (index >= m_children.size()) + return nullptr; - return m_children[index].get(); + return m_children[index].get(); } -TreeNode *TreeNode::GetChild (std::size_t index) { - if (index >= m_children.size()) - return nullptr; +TreeNode *TreeNode::GetChild(std::size_t index) { + if (index >= m_children.size()) + return nullptr; - return m_children[index].get(); + return m_children[index].get(); } NodeType TreeNode::GetType() const { - return m_type; + return m_type; } const std::string &TreeNode::GetName() const { - return m_name; + return m_name; } const FrameInfo *TreeNode::GetFrame() const { - return m_frame.get(); + return m_frame.get(); } const SignalInfo *TreeNode::GetSignal() const { - return m_signal.get(); + return m_signal.get(); } diff --git a/tree_node.h b/tree_node.h index 404a1c8..a047e20 100644 --- a/tree_node.h +++ b/tree_node.h @@ -12,10 +12,10 @@ #ifndef TREE_NODE_H #define TREE_NODE_H +#include +#include #include #include -#include -#include #include "frame_info.h" #include "signal_info.h" @@ -24,16 +24,16 @@ * @brief Type of a tree node. */ enum class NodeType { - Root, - Frame, - Signal + Root, + Frame, + Signal }; /** * @brief Tree node for later use in model/view or other hierarchy consumers. */ class TreeNode { - public: +public: /** * @brief Create root node. */ @@ -43,27 +43,27 @@ class TreeNode { * @brief Create frame node. * @param frame Frame payload. */ - explicit TreeNode (const FrameInfo &frame); + explicit TreeNode(const FrameInfo &frame); /** * @brief Create signal node. * @param signal Signal payload. */ - explicit TreeNode (const SignalInfo &signal); + explicit TreeNode(const SignalInfo &signal); ~TreeNode() = default; - TreeNode (const TreeNode &) = delete; - TreeNode &operator= (const TreeNode &) = delete; + TreeNode(const TreeNode &) = delete; + TreeNode &operator=(const TreeNode &) = delete; - TreeNode (TreeNode &&) = default; - TreeNode &operator= (TreeNode &&) = default; + TreeNode(TreeNode &&) = default; + TreeNode &operator=(TreeNode &&) = default; /** * @brief Add child node. * @param child Child node to add. */ - void AddChild (std::unique_ptr child); + void AddChild(std::unique_ptr child); /** * @brief Get child count. @@ -76,14 +76,14 @@ class TreeNode { * @param index Child index. * @return Child pointer or nullptr if index is invalid. */ - const TreeNode *GetChild (std::size_t index) const; + const TreeNode *GetChild(std::size_t index) const; /** * @brief Get mutable child by index. * @param index Child index. * @return Child pointer or nullptr if index is invalid. */ - TreeNode *GetChild (std::size_t index); + TreeNode *GetChild(std::size_t index); /** * @brief Get node type. @@ -109,10 +109,10 @@ class TreeNode { */ const SignalInfo *GetSignal() const; - private: +private: NodeType m_type; std::string m_name; - std::vector > m_children; + std::vector> m_children; std::unique_ptr m_frame; std::unique_ptr m_signal; }; diff --git a/typefactory.h b/typefactory.h index 4f8909f..b29d14f 100644 --- a/typefactory.h +++ b/typefactory.h @@ -7,7 +7,7 @@ #include #include #include -#include // std::move +#include // std::move /** * @brief Registry-based factory for creating objects by runtime identifier. @@ -55,15 +55,15 @@ * (void)b->get(); * @endcode */ -template +template class TypeFactory { public: - using BasePtr = std::shared_ptr; - using CreatorFn = BasePtr (*)(Args...); + using BasePtr = std::shared_ptr; + using CreatorFn = BasePtr (*)(Args...); - TypeFactory() = default; + TypeFactory() = default; - /** + /** * @brief Registers a Derived type under the given id. * * Requirements (checked at compile-time): @@ -72,47 +72,47 @@ public: * * Re-registering the same id overwrites the previous entry ("last wins"). */ - template - void registerType(const ClassId& id) { - static_assert(std::is_base_of_v, - "Derived must inherit from BaseClass"); - static_assert(std::is_constructible_v, - "Derived must be constructible from Args..."); + template + void registerType(const ClassId &id) { + static_assert(std::is_base_of_v, + "Derived must inherit from BaseClass"); + static_assert(std::is_constructible_v, + "Derived must be constructible from Args..."); - classes.insert_or_assign(id, &instantiate); - } + classes.insert_or_assign(id, &instantiate); + } - /** + /** * @brief Returns creator function for the given id. * @throws std::out_of_range when id is not registered. */ - [[nodiscard]] CreatorFn creator(const ClassId& id) const { - return classes.at(id); - } + [[nodiscard]] CreatorFn creator(const ClassId &id) const { + return classes.at(id); + } - /** + /** * @brief Creates an instance for the given id using provided arguments. * @throws std::out_of_range when id is not registered. */ - [[nodiscard]] BasePtr create(const ClassId& id, Args... args) const { - return creator(id)(std::move(args)...); - } + [[nodiscard]] BasePtr create(const ClassId &id, Args... args) const { + return creator(id)(std::move(args)...); + } - /** + /** * @brief Checks whether an id is registered. */ - [[nodiscard]] bool contains(const ClassId& id) const { - return classes.find(id) != classes.end(); - } + [[nodiscard]] bool contains(const ClassId &id) const { + return classes.find(id) != classes.end(); + } protected: - // Protected by design: derived factories may extend/inspect the registry. - std::unordered_map classes; + // Protected by design: derived factories may extend/inspect the registry. + std::unordered_map classes; private: - template - static BasePtr instantiate(Args... args) { - return std::make_shared(std::move(args)...); - } + template + static BasePtr instantiate(Args... args) { + return std::make_shared(std::move(args)...); + } }; -#endif // TYPEFACTORY_H +#endif// TYPEFACTORY_H