10 std::uint32_t startBit;
13 std::vector<std::uint8_t> data;
15 std::int64_t rawValue;
21Q_DECLARE_METATYPE(DecodeCase)
23class DbcDecoderTest :
public QObject {
31void DbcDecoderTest::decode_data() {
32 QTest::addColumn<DecodeCase>(
"test");
33 const DecodeCase cases[] = {
34 {
"Motorola reproduction", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12, 0x34},
true, 0x1234, 1.0, 0.0, 4660.0},
35 {
"Motorola within byte", ByteOrder::Motorola, 5U, 4U, ValueType::Unsigned, {0xAC},
true, 11, 1.0, 0.0, 11.0},
36 {
"Motorola unaligned crossing", ByteOrder::Motorola, 3U, 12U, ValueType::Unsigned, {0xAB, 0xCD},
true, 0xBCD, 1.0, 0.0, 3021.0},
37 {
"Motorola starts at bit zero", ByteOrder::Motorola, 0U, 2U, ValueType::Unsigned, {0x01, 0x80},
true, 3, 1.0, 0.0, 3.0},
38 {
"Motorola second byte", ByteOrder::Motorola, 15U, 16U, ValueType::Unsigned, {0xFF, 0x12, 0x34},
true, 0x1234, 1.0, 0.0, 4660.0},
39 {
"Motorola signed scaled", ByteOrder::Motorola, 7U, 16U, ValueType::Signed, {0xFF, 0xFE},
true, -2, 0.5, 10.0, 9.0},
40 {
"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},
41 {
"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},
42 {
"Motorola short payload", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12},
false, 0, 1.0, 0.0, 0.0},
43 {
"Motorola empty payload", ByteOrder::Motorola, 7U, 8U, ValueType::Unsigned, {},
false, 0, 1.0, 0.0, 0.0},
44 {
"Motorola large start", ByteOrder::Motorola, std::numeric_limits<std::uint32_t>::max(), 8U, ValueType::Unsigned, {0xFF},
false, 0, 1.0, 0.0, 0.0},
45 {
"Motorola zero length", ByteOrder::Motorola, 7U, 0U, ValueType::Unsigned, {0xFF},
false, 0, 1.0, 0.0, 0.0},
46 {
"Motorola excessive length", ByteOrder::Motorola, 7U, 65U, ValueType::Unsigned,
47 std::vector<std::uint8_t>(9U, 0xFF),
false, 0, 1.0, 0.0, 0.0},
48 {
"Intel regression", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12, 0x34},
true, 0x3412, 1.0, 0.0, 13330.0},
49 {
"Intel signed regression", ByteOrder::Intel, 0U, 16U, ValueType::Signed, {0xFE, 0xFF},
true, -2, 0.5, 10.0, 9.0},
50 {
"Intel short payload", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12},
false, 0, 1.0, 0.0, 0.0}};
52 for (
const auto &test: cases)
53 QTest::newRow(test.name) << test;
56void DbcDecoderTest::decode() {
57 QFETCH(DecodeCase, test);
59 signal.
name = test.name;
62 signal.
length = test.length;
64 signal.
factor = test.factor;
65 signal.
offset = test.offset;
68 definition.
canId = 0x123U;
69 definition.
dlc =
static_cast<std::uint8_t
>(test.data.size());
70 definition.signals.push_back(signal);
72 database.frames.push_back(definition);
73 database.frameIndexByKey.emplace(
FrameKey(definition.
canId,
false), 0U);
77 frame.
data = test.data;
79 const bool passed = result.
valid &&
81 (result.signals.size() == 1U) &&
82 (result.signals[0].
definition == &database.frames[0].signals[0]) &&
83 (result.signals[0].
valid == test.valid) &&
84 (!test.valid || (((test.valueType == ValueType::Signed)
85 ? (std::get_if<std::int64_t>(&result.signals[0].rawValue) &&
86 std::get<std::int64_t>(result.signals[0].rawValue) == test.rawValue)
87 : (std::get_if<std::uint64_t>(&result.signals[0].rawValue) &&
88 std::get<std::uint64_t>(result.signals[0].rawValue) ==
89 static_cast<std::uint64_t>(test.rawValue))) &&
90 (result.signals[0].physicalValue == test.physicalValue)));
91 QVERIFY2(passed, test.name);
94void DbcDecoderTest::boundaries() {
95 for (
ByteOrder order: {ByteOrder::Intel, ByteOrder::Motorola}) {
96 for (
ValueType type: {ValueType::Unsigned, ValueType::Signed}) {
97 for (std::uint64_t bits: {std::uint64_t(0U), std::uint64_t(0x7FFFFFFFFFFFFFFFULL),
98 std::uint64_t(0x8000000000000000ULL),
99 std::uint64_t(0x8000000000000001ULL),
100 std::uint64_t(0xFFFFFFFFFFFFFFFFULL)}) {
104 signal.
startBit = order == ByteOrder::Intel ? 0U : 7U;
110 definition.signals.push_back(signal);
111 database.frames.push_back(definition);
112 database.frameIndexByKey.emplace(
FrameKey(0U,
false), 0U);
114 for (
unsigned byte = 0U;
byte < 8U; ++byte) {
115 const unsigned shift = (order == ByteOrder::Intel ? byte : 7U - byte) * 8U;
116 frame.
data.push_back(
static_cast<std::uint8_t
>(bits >> shift));
119 const std::int64_t signedExpected = bits <= 0x7FFFFFFFFFFFFFFFULL
120 ?
static_cast<std::int64_t
>(bits)
121 : std::numeric_limits<std::int64_t>::min() +
122 static_cast<std::int64_t>(bits - 0x8000000000000000ULL);
123 const auto &decoded = result.signals.at(0U);
124 const auto expected = type == ValueType::Unsigned
125 ? std::variant<std::int64_t, std::uint64_t>(bits)
126 : std::variant<std::int64_t, std::uint64_t>(signedExpected);
127 const double physical = (type == ValueType::Unsigned
128 ?
static_cast<double>(bits)
129 : static_cast<double>(signedExpected)) *
132 std::ostringstream actualText;
133 std::ostringstream expectedText;
134 if (
const auto *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
135 actualText << *signedValue;
137 actualText << std::get<std::uint64_t>(decoded.rawValue);
138 if (type == ValueType::Unsigned)
139 expectedText << bits;
141 expectedText << signedExpected;
142 QVERIFY2(decoded.valid && decoded.rawValue == expected &&
143 decoded.physicalValue == physical && actualText.str() == expectedText.str(),
144 expectedText.str().c_str());
150int RunDecoderTests(
int argc,
char **argv) {
151 DbcDecoderTest tests;
152 return QTest::qExec(&tests, argc, argv);
155#include "dbc_decoder_test.moc"
Runtime CAN decoder using prebuilt decode database.
DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
Decode one raw CAN frame.
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
ByteOrder
Signal byte order used for runtime decoding.
ValueType
Signal numeric type.
Runtime decode database with fast lookup by CAN ID.
Runtime-ready frame definition.
Runtime-ready signal definition.
const DecodeFrame * definition
Key for fast frame lookup.
Raw CAN frame used for runtime or trace decoding.
std::vector< std::uint8_t > data