Added decoding support to runtime decode.

This commit is contained in:
2026-03-13 13:30:38 -04:00
parent cb20f5fe55
commit a53a5dfed3
12 changed files with 562 additions and 56 deletions

View File

@@ -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

View File

@@ -9,7 +9,7 @@
* @brief Parsed DBC content stored in a simple internal form.
*/
struct DbcDatabase {
std::vector<FrameInfo> frames; /**< All frames found in DBC file. */
std::vector<FrameInfo> frames; /**< All frames found in the DBC file. */
};
#endif /* DBC_DATABASE_H */

45
dbc_decode_builder.cpp Normal file
View File

@@ -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;
}

20
dbc_decode_builder.h Normal file
View File

@@ -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 */

146
dbc_decoder.cpp Normal file
View File

@@ -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<FrameKey, std::size_t, FrameKeyHasher>::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<std::int64_t> (unsignedValue);
decoded.physicalValue =
(static_cast<double> (decoded.rawValue) * signal.factor) + signal.offset;
decoded.valid = true;
result.signals.push_back (decoded);
}
return result;
}
bool DbcDecoder::ExtractUnsigned (const std::vector<std::uint8_t> &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<std::uint8_t> &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<std::uint64_t> ((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
value |= bitValue;
}
return true;
}
bool DbcDecoder::ExtractMotorola (const std::vector<std::uint8_t> &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<std::int32_t> (startBit);
for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
if (currentBit < 0)
return false;
const std::uint32_t absoluteBit = static_cast<std::uint32_t> (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<std::uint64_t> ((data[byteIndex] >> bitInByte) & 0x01U);
if ((absoluteBit % 8U) == 7U)
currentBit = static_cast<std::int32_t> ((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<std::int64_t> (value);
const std::uint64_t signMask = (static_cast<std::uint64_t> (1U) << (bitLength - 1U));
const std::uint64_t valueMask = (static_cast<std::uint64_t> (1U) << bitLength) - 1U;
value &= valueMask;
if ((value & signMask) == 0U)
return static_cast<std::int64_t> (value);
return static_cast<std::int64_t> (value | (~valueMask));
}

99
dbc_decoder.h Normal file
View File

@@ -0,0 +1,99 @@
#ifndef DBC_DECODER_H
#define DBC_DECODER_H
#include <vector>
#include <cstdint>
#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<std::uint8_t> 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<DecodedSignalValue> 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<std::uint8_t> &data,
const DecodeSignal &signal,
std::uint64_t &value);
static bool ExtractIntel (const std::vector<std::uint8_t> &data,
std::uint32_t startBit,
std::uint32_t length,
std::uint64_t &value);
static bool ExtractMotorola (const std::vector<std::uint8_t> &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 */

View File

@@ -3,7 +3,6 @@
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <algorithm>
#include <cctype>
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<unsigned char> (text[begin])))
while ((begin < text.size()) &&
std::isspace (static_cast<unsigned char> (text[begin])))
++begin;
std::string::size_type end = text.size();
while ((end > begin) && std::isspace (static_cast<unsigned char> (text[end - 1U])))
while ((end > begin) &&
std::isspace (static_cast<unsigned char> (text[end - 1U])))
--end;
return text.substr (begin, end - begin);
@@ -86,13 +87,29 @@ std::vector<std::string> 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];
}

View File

@@ -37,14 +37,21 @@ class DbcParser {
static bool IsCommentLine (const std::string &line);
static std::string Trim (const std::string &text);
static std::vector<std::string> 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);
};

126
decode_database.h Normal file
View File

@@ -0,0 +1,126 @@
#ifndef DECODE_DATABASE_H
#define DECODE_DATABASE_H
#include <string>
#include <vector>
#include <unordered_map>
#include <cstdint>
/**
* @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<std::string> 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<DecodeSignal> 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<std::size_t> (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<DecodeFrame> frames;
std::unordered_map<FrameKey, std::size_t, FrameKeyHasher> frameIndexByKey;
};
#endif /* DECODE_DATABASE_H */

View File

@@ -12,7 +12,8 @@
*/
struct FrameInfo {
std::string name; /**< Frame name. */
std::uint32_t canId; /**< Raw CAN identifier from DBC. */
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. */
@@ -23,6 +24,7 @@ struct FrameInfo {
FrameInfo()
: name()
, canId (0U)
, isExtended (false)
, pgn (0U)
, hasPgn (false)
, dlc (0U)

View File

@@ -1,19 +1,13 @@
#include <iostream>
#include <iomanip>
#include <memory>
#include <vector>
#include <cstddef>
#include "dbc_parser.h"
#include "dbc_tree_builder.h"
#include "tree_node.h"
static void PrintReceivers (const std::vector<std::string> &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<unsigned int> (frame->dlc)
<< " tx=" << frame->transmitter;
std::cout << " id=0x" << std::hex << frame->canId << std::dec
<< " ext=" << (frame->isExtended ? "yes" : "no")
<< " dlc=" << static_cast<unsigned int> (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 <file.dbc>\n";
@@ -86,10 +93,29 @@ int main (int argc, char *argv[]) {
DbcParser parser;
DbcDatabase database = parser.ParseFile (argv[1]);
DbcTreeBuilder builder;
std::unique_ptr<TreeNode> root = builder.Build (database);
DbcTreeBuilder treeBuilder;
std::unique_ptr<TreeNode> 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;

View File

@@ -19,7 +19,7 @@ struct SignalInfo {
double minimum; /**< Minimum physical value. */
double maximum; /**< Maximum physical value. */
std::string unit; /**< Physical unit. */
std::vector<std::string> receivers; /**< Receivers of this signal. */
std::vector<std::string> receivers; /**< Signal receivers. */
std::string comment; /**< Optional signal comment. */
SignalInfo()