From a53a5dfed3ff803e9eeb6b917b470d2cba5058e0 Mon Sep 17 00:00:00 2001 From: deeaitch Date: Fri, 13 Mar 2026 13:30:38 -0400 Subject: [PATCH] Added decoding support to runtime decode. --- dbc.pro | 5 ++ dbc_database.h | 2 +- dbc_decode_builder.cpp | 45 +++++++++++++ dbc_decode_builder.h | 20 ++++++ dbc_decoder.cpp | 146 +++++++++++++++++++++++++++++++++++++++++ dbc_decoder.h | 99 ++++++++++++++++++++++++++++ dbc_parser.cpp | 68 +++++++++++++------ dbc_parser.h | 11 +++- decode_database.h | 126 +++++++++++++++++++++++++++++++++++ frame_info.h | 18 ++--- main.cpp | 76 ++++++++++++++------- signal_info.h | 2 +- 12 files changed, 562 insertions(+), 56 deletions(-) create mode 100644 dbc_decode_builder.cpp create mode 100644 dbc_decode_builder.h create mode 100644 dbc_decoder.cpp create mode 100644 dbc_decoder.h create mode 100644 decode_database.h diff --git a/dbc.pro b/dbc.pro index b646ea7..06d7c4b 100644 --- a/dbc.pro +++ b/dbc.pro @@ -4,6 +4,8 @@ CONFIG -= app_bundle CONFIG -= qt SOURCES += \ + dbc_decode_builder.cpp \ + dbc_decoder.cpp \ dbc_parser.cpp \ dbc_tree_builder.cpp \ main.cpp \ @@ -11,8 +13,11 @@ SOURCES += \ HEADERS += \ dbc_database.h \ + dbc_decode_builder.h \ + dbc_decoder.h \ dbc_parser.h \ dbc_tree_builder.h \ + decode_database.h \ frame_info.h \ signal_info.h \ tree_node.h diff --git a/dbc_database.h b/dbc_database.h index ba52339..bfdac0e 100644 --- a/dbc_database.h +++ b/dbc_database.h @@ -9,7 +9,7 @@ * @brief Parsed DBC content stored in a simple internal form. */ struct DbcDatabase { - std::vector frames; /**< All frames found in 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 new file mode 100644 index 0000000..18df709 --- /dev/null +++ b/dbc_decode_builder.cpp @@ -0,0 +1,45 @@ +#include "dbc_decode_builder.h" + +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; + + 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; + + 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); + } + + result.frames.push_back (targetFrame); + result.frameIndexByKey[FrameKey (targetFrame.canId, targetFrame.isExtended)] = + result.frames.size() - 1U; + } + + return result; +} diff --git a/dbc_decode_builder.h b/dbc_decode_builder.h new file mode 100644 index 0000000..ad65ca4 --- /dev/null +++ b/dbc_decode_builder.h @@ -0,0 +1,20 @@ +#ifndef DBC_DECODE_BUILDER_H +#define DBC_DECODE_BUILDER_H + +#include "dbc_database.h" +#include "decode_database.h" + +/** + * @brief Converts parsed DBC data into runtime decode database. + */ +class DbcDecodeBuilder { + public: + /** + * @brief Build runtime decode database. + * @param source Parsed DBC database. + * @return Runtime-ready decode database. + */ + DecodeDatabase Build (const DbcDatabase &source) const; +}; + +#endif /* DBC_DECODE_BUILDER_H */ diff --git a/dbc_decoder.cpp b/dbc_decoder.cpp new file mode 100644 index 0000000..0d564b4 --- /dev/null +++ b/dbc_decoder.cpp @@ -0,0 +1,146 @@ +#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); + + if (it == database.frameIndexByKey.end()) + return nullptr; + + const std::size_t index = it->second; + if (index >= database.frames.size()) + return nullptr; + + 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); + + if (definition == nullptr) + return result; + + 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; + + decoded.definition = &signal; + + 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 = static_cast (unsignedValue); + + decoded.physicalValue = + (static_cast (decoded.rawValue) * signal.factor) + signal.offset; + decoded.valid = true; + + result.signals.push_back (decoded); + } + + 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; + + if (signal.byteOrder == ByteOrder::Intel) + return ExtractIntel (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; + + 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; + + const std::uint64_t bitValue = + (static_cast ((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex); + + value |= bitValue; + } + + return true; +} + +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 + * - crossing byte boundary moves to the next byte, bit 7 + */ + + value = 0U; + + std::int32_t currentBit = static_cast (startBit); + + for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) { + if (currentBit < 0) + return false; + + const std::uint32_t absoluteBit = static_cast (currentBit); + const std::uint32_t byteIndex = absoluteBit / 8U; + const std::uint32_t bitFromMsb = absoluteBit % 8U; + const std::uint32_t bitInByte = 7U - bitFromMsb; + + if (byteIndex >= data.size()) + return false; + + value <<= 1U; + value |= static_cast ((data[byteIndex] >> bitInByte) & 0x01U); + + if ((absoluteBit % 8U) == 7U) + currentBit = static_cast ((byteIndex + 1U) * 8U); + else + --currentBit; + } + + return true; +} + +std::int64_t DbcDecoder::SignExtend (std::uint64_t value, std::uint32_t bitLength) { + if ((bitLength == 0U) || (bitLength >= 64U)) + return static_cast (value); + + const std::uint64_t signMask = (static_cast (1U) << (bitLength - 1U)); + const std::uint64_t valueMask = (static_cast (1U) << bitLength) - 1U; + + value &= valueMask; + + if ((value & signMask) == 0U) + return static_cast (value); + + return static_cast (value | (~valueMask)); +} diff --git a/dbc_decoder.h b/dbc_decoder.h new file mode 100644 index 0000000..6c14d71 --- /dev/null +++ b/dbc_decoder.h @@ -0,0 +1,99 @@ +#ifndef DBC_DECODER_H +#define DBC_DECODER_H + +#include +#include + +#include "decode_database.h" + +/** + * @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. */ + + RawCanFrame() + : canId (0U) + , isExtended (false) + , data() { + } +}; + +/** + * @brief One decoded signal value. + */ +struct DecodedSignalValue { + const DecodeSignal *definition; /**< Signal definition. */ + std::int64_t rawValue; /**< Extracted raw integer value. */ + double physicalValue; /**< Converted physical value. */ + bool valid; /**< true if decoding succeeded. */ + + DecodedSignalValue() + : definition (nullptr) + , rawValue (0) + , 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. */ + + DecodedFrameValue() + : definition (nullptr) + , signals() + , valid (false) { + } +}; + +/** + * @brief Runtime CAN decoder using prebuilt decode database. + */ +class DbcDecoder { + public: + /** + * @brief Find frame definition by CAN ID. + * @param database Runtime decode database. + * @param canId Normalized CAN ID. + * @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; + + /** + * @brief Decode one raw CAN frame. + * @param database Runtime decode database. + * @param frame Raw CAN frame. + * @return Decoded frame value. + */ + DecodedFrameValue Decode (const DecodeDatabase &database, + const RawCanFrame &frame) const; + + 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 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); +}; + +#endif /* DBC_DECODER_H */ diff --git a/dbc_parser.cpp b/dbc_parser.cpp index a039312..8ba4246 100644 --- a/dbc_parser.cpp +++ b/dbc_parser.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include namespace { @@ -14,11 +13,13 @@ namespace { */ std::string TrimText (const std::string &text) { std::string::size_type begin = 0U; - while ((begin < text.size()) && std::isspace (static_cast (text[begin]))) + 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]))) + while ((end > begin) && + std::isspace (static_cast (text[end - 1U]))) --end; return text.substr (begin, end - begin); @@ -86,13 +87,29 @@ std::vector DbcParser::SplitReceivers (const std::string &text) { return receivers; } -std::uint32_t DbcParser::TryExtractPgn (std::uint32_t canId, bool &hasPgn) { +void DbcParser::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; + } +} + +std::uint32_t DbcParser::TryExtractPgn (std::uint32_t canId, bool isExtended, bool &hasPgn) { hasPgn = false; - /* - * Very simplified J1939 PGN extraction. - * Assumes 29-bit identifier. - */ + if (!isExtended) + return 0U; + if ((canId & 0x1FFFFFFFU) != canId) return 0U; @@ -114,20 +131,22 @@ std::uint32_t DbcParser::TryExtractPgn (std::uint32_t canId, bool &hasPgn) { FrameInfo DbcParser::ParseFrameLine (const std::string &line) { /* * Example: - * BO_ 256 EngineData: 8 Vector__XXX + * BO_ 256 EngineData: 8 EEC1 */ std::istringstream stream (line); std::string token; FrameInfo frame; + std::uint32_t rawCanId = 0U; stream >> token; if (token != "BO_") throw std::runtime_error ("Invalid frame line: " + line); - stream >> frame.canId; - stream >> token; + stream >> rawCanId; + NormalizeCanId (rawCanId, frame.canId, frame.isExtended); + stream >> token; if (token.empty()) throw std::runtime_error ("Missing frame name: " + line); @@ -143,7 +162,7 @@ FrameInfo DbcParser::ParseFrameLine (const std::string &line) { } stream >> frame.transmitter; - frame.pgn = TryExtractPgn (frame.canId, frame.hasPgn); + frame.pgn = TryExtractPgn (frame.canId, frame.isExtended, frame.hasPgn); return frame; } @@ -151,7 +170,7 @@ FrameInfo DbcParser::ParseFrameLine (const std::string &line) { SignalInfo DbcParser::ParseSignalLine (const std::string &line) { /* * Example: - * SG_ EngineSpeed : 0|16@1+ (0.125,0) [0|8000] "rpm" Vector__XXX + * SG_ EngineSpeed : 0|16@1+ (0.125,0) [0|8000] "rpm" ECU1,ECU2 */ SignalInfo signal; @@ -258,8 +277,12 @@ void DbcParser::ParseCommentLine (const std::string &line, DbcDatabase &database stream >> token; if (token == "BO_") { + std::uint32_t rawCanId = 0U; std::uint32_t canId = 0U; - stream >> canId; + bool isExtended = false; + + stream >> rawCanId; + NormalizeCanId (rawCanId, canId, isExtended); const std::string::size_type quoteBegin = line.find ('"'); const std::string::size_type quoteEnd = line.rfind ('"'); @@ -269,16 +292,20 @@ void DbcParser::ParseCommentLine (const std::string &line, DbcDatabase &database (quoteEnd <= quoteBegin)) return; - FrameInfo *frame = FindFrameById (database, canId); + 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 >> canId; + stream >> rawCanId; stream >> signalName; + NormalizeCanId (rawCanId, canId, isExtended); + const std::string::size_type quoteBegin = line.find ('"'); const std::string::size_type quoteEnd = line.rfind ('"'); @@ -287,7 +314,7 @@ void DbcParser::ParseCommentLine (const std::string &line, DbcDatabase &database (quoteEnd <= quoteBegin)) return; - FrameInfo *frame = FindFrameById (database, canId); + FrameInfo *frame = FindFrameById (database, canId, isExtended); if (frame != nullptr) { SignalInfo *signal = FindSignalByName (*frame, signalName); if (signal != nullptr) @@ -296,9 +323,12 @@ void DbcParser::ParseCommentLine (const std::string &line, DbcDatabase &database } } -FrameInfo *DbcParser::FindFrameById (DbcDatabase &database, std::uint32_t canId) { +FrameInfo *DbcParser::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) + if ((database.frames[index].canId == canId) && + (database.frames[index].isExtended == isExtended)) return &database.frames[index]; } diff --git a/dbc_parser.h b/dbc_parser.h index 8e0c0c7..d0586a5 100644 --- a/dbc_parser.h +++ b/dbc_parser.h @@ -37,14 +37,21 @@ class DbcParser { static bool IsCommentLine (const std::string &line); static std::string Trim (const std::string &text); static std::vector SplitReceivers (const std::string &text); - static std::uint32_t TryExtractPgn (std::uint32_t canId, bool &hasPgn); + static std::uint32_t TryExtractPgn (std::uint32_t canId, bool isExtended, bool &hasPgn); + + static void NormalizeCanId (std::uint32_t rawCanId, + std::uint32_t &normalizedCanId, + bool &isExtended); static FrameInfo ParseFrameLine (const std::string &line); static SignalInfo ParseSignalLine (const std::string &line); static void ParseCommentLine (const std::string &line, DbcDatabase &database); - static FrameInfo *FindFrameById (DbcDatabase &database, std::uint32_t canId); + static FrameInfo *FindFrameById (DbcDatabase &database, + std::uint32_t canId, + bool isExtended); + static SignalInfo *FindSignalByName (FrameInfo &frame, const std::string &signalName); }; diff --git a/decode_database.h b/decode_database.h new file mode 100644 index 0000000..07b3c35 --- /dev/null +++ b/decode_database.h @@ -0,0 +1,126 @@ +#ifndef DECODE_DATABASE_H +#define DECODE_DATABASE_H + +#include +#include +#include +#include + +/** + * @brief Signal byte order used for runtime decoding. + */ +enum class ByteOrder { + Intel, + Motorola +}; + +/** + * @brief Signal numeric type. + */ +enum class ValueType { + 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. */ + + 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. */ + + 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; + + FrameKey() + : canId (0U) + , isExtended (false) { + } + + FrameKey (std::uint32_t id, bool extended) + : canId (id) + , isExtended (extended) { + } + + 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; + } +}; + +/** + * @brief Runtime decode database with fast lookup by CAN ID. + */ +struct DecodeDatabase { + std::vector frames; + std::unordered_map frameIndexByKey; +}; + +#endif /* DECODE_DATABASE_H */ diff --git a/frame_info.h b/frame_info.h index 7f24ed9..42153f1 100644 --- a/frame_info.h +++ b/frame_info.h @@ -11,18 +11,20 @@ * @brief Describes one CAN frame from a DBC file. */ struct FrameInfo { - std::string name; /**< Frame name. */ - std::uint32_t canId; /**< Raw CAN identifier from DBC. */ - 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) diff --git a/main.cpp b/main.cpp index 4ed5c3a..0d0a8cc 100644 --- a/main.cpp +++ b/main.cpp @@ -1,19 +1,13 @@ #include +#include #include +#include #include #include "dbc_parser.h" #include "dbc_tree_builder.h" -#include "tree_node.h" - -static void PrintReceivers (const std::vector &receivers) { - for (std::size_t index = 0U; index < receivers.size(); ++index) { - if (index != 0U) - std::cout << ","; - - std::cout << receivers[index]; - } -} +#include "dbc_decode_builder.h" +#include "dbc_decoder.h" static void PrintTree (const TreeNode *node, int indent) { if (node == nullptr) @@ -32,15 +26,12 @@ static void PrintTree (const TreeNode *node, int indent) { std::cout << "[frame] " << node->GetName(); if (frame != nullptr) { - std::cout << " id=" << frame->canId - << " dlc=" << static_cast (frame->dlc) - << " tx=" << frame->transmitter; + 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->comment.empty()) - std::cout << " comment=\"" << frame->comment << "\""; } std::cout << "\n"; @@ -54,13 +45,7 @@ static void PrintTree (const TreeNode *node, int indent) { if (signal != nullptr) { std::cout << " start=" << signal->startBit << " len=" << signal->length - << " unit=" << signal->unit - << " rx="; - - PrintReceivers (signal->receivers); - - if (!signal->comment.empty()) - std::cout << " comment=\"" << signal->comment << "\""; + << " unit=" << signal->unit; } std::cout << "\n"; @@ -76,6 +61,28 @@ static void PrintTree (const TreeNode *node, int indent) { PrintTree (node->GetChild (i), indent + 1); } +static void PrintDecodedFrame (const DecodedFrameValue &decoded) { + if (!decoded.valid || (decoded.definition == nullptr)) { + std::cout << "No frame definition found.\n"; + return; + } + + std::cout << "Decoded frame: " << decoded.definition->name << "\n"; + + 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=" << signal.rawValue + << " physical=" << signal.physicalValue + << " " << signal.definition->unit + << "\n"; + } +} + int main (int argc, char *argv[]) { if (argc < 2) { std::cerr << "Usage: dbc_demo \n"; @@ -86,10 +93,29 @@ int main (int argc, char *argv[]) { DbcParser parser; DbcDatabase database = parser.ParseFile (argv[1]); - DbcTreeBuilder builder; - std::unique_ptr root = builder.Build (database); + 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); + + 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; diff --git a/signal_info.h b/signal_info.h index 55737bc..0b99db3 100644 --- a/signal_info.h +++ b/signal_info.h @@ -19,7 +19,7 @@ struct SignalInfo { double minimum; /**< Minimum physical value. */ double maximum; /**< Maximum physical value. */ std::string unit; /**< Physical unit. */ - std::vector receivers; /**< Receivers of this signal. */ + std::vector receivers; /**< Signal receivers. */ std::string comment; /**< Optional signal comment. */ SignalInfo()