DBC Framework
DBC parsing and CAN signal decoding framework
Loading...
Searching...
No Matches
dbc_decoder.cpp
Go to the documentation of this file.
1
12#include "dbc_decoder.h"
13
15 std::uint32_t canId,
16 bool isExtended) const {
17 const FrameKey key(canId, isExtended);
18 const std::unordered_map<FrameKey, std::size_t, FrameKeyHasher>::const_iterator it =
19 database.frameIndexByKey.find(key);
20
21 if (it == database.frameIndexByKey.end())
22 return nullptr;
23
24 const std::size_t index = it->second;
25 if (index >= database.frames.size())
26 return nullptr;
27
28 return &database.frames[index];
29}
30
32 const RawCanFrame &frame) const {
33 DecodedFrameValue result;
34 const DecodeFrame *definition = FindFrame(database, frame.canId, frame.isExtended);
35
36 if (definition == nullptr)
37 return result;
38
39 result.definition = definition;
40 result.valid = true;
41
42 for (std::size_t signalIndex = 0U; signalIndex < definition->signals.size(); ++signalIndex) {
43 const DecodeSignal &signal = definition->signals[signalIndex];
44 DecodedSignalValue decoded;
45 std::uint64_t unsignedValue = 0U;
46
47 decoded.definition = &signal;
48
49 if (!ExtractUnsigned(frame.data, signal, unsignedValue)) {
50 decoded.valid = false;
51 result.signals.push_back(decoded);
52 continue;
53 }
54
55 if (signal.valueType == ValueType::Signed)
56 decoded.rawValue = SignExtend(unsignedValue, signal.length);
57 else
58 decoded.rawValue = unsignedValue;
59
60 double numericValue;
61 if (const auto *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
62 numericValue = static_cast<double>(*signedValue);
63 else
64 numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
65 decoded.physicalValue = numericValue * signal.factor + signal.offset;
66 decoded.valid = true;
67
68 result.signals.push_back(decoded);
69 }
70
71 return result;
72}
73
74bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
75 const DecodeSignal &signal,
76 std::uint64_t &value) {
77 if ((signal.length == 0U) || (signal.length > 64U))
78 return false;
79
80 if (signal.byteOrder == ByteOrder::Intel)
81 return ExtractIntel(data, signal.startBit, signal.length, value);
82
83 return ExtractMotorola(data, signal.startBit, signal.length, value);
84}
85
86bool DbcDecoder::ExtractIntel(const std::vector<std::uint8_t> &data,
87 std::uint32_t startBit,
88 std::uint32_t length,
89 std::uint64_t &value) {
90 value = 0U;
91
92 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
93 const std::uint32_t absoluteBit = startBit + bitIndex;
94 const std::uint32_t byteIndex = absoluteBit / 8U;
95 const std::uint32_t bitInByte = absoluteBit % 8U;
96
97 if (byteIndex >= data.size())
98 return false;
99
100 const std::uint64_t bitValue =
101 (static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
102
103 value |= bitValue;
104 }
105
106 return true;
107}
108
109bool DbcDecoder::ExtractMotorola(const std::vector<std::uint8_t> &data,
110 std::uint32_t startBit,
111 std::uint32_t length,
112 std::uint64_t &value) {
113 /*
114 * DBC Motorola bit numbering:
115 * - startBit points to the most significant bit of the signal
116 * - inside a byte, bit numbering goes 7..0
117 * - crossing byte boundary moves to the next byte, bit 7
118 * Example: a signal starting at 7 follows 7..0, 15..8, 23..16.
119 */
120
121 value = 0U;
122
123 std::size_t byteIndex = startBit / 8U;
124 std::uint32_t bitInByte = startBit % 8U;
125
126 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
127 if (byteIndex >= data.size())
128 return false;
129
130 value <<= 1U;
131 value |= static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U);
132
133 if (bitInByte == 0U) {
134 ++byteIndex;
135 bitInByte = 7U;
136 } else
137 --bitInByte;
138 }
139
140 return true;
141}
142
143std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
144 if ((bitLength == 0U) || (bitLength > 64U))
145 return 0;
146
147 const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
148 const std::uint64_t valueMask = (bitLength == 64U)
149 ? ~std::uint64_t(0U)
150 : (std::uint64_t(1U) << bitLength) - 1U;
151 value &= valueMask;
152
153 if ((value & signMask) == 0U)
154 return static_cast<std::int64_t>(value);
155
156 // The complemented magnitude fits int64_t, including for INT64_MIN.
157 return -1 - static_cast<std::int64_t>((~value) & valueMask);
158}
DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
Decode one raw CAN frame.
const DecodeFrame * FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const
Find frame definition by CAN ID.
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
Runtime decode database with fast lookup by CAN ID.
Runtime-ready frame definition.
Runtime-ready signal definition.
ValueType valueType
std::uint32_t startBit
ByteOrder byteOrder
std::uint32_t length
Fully decoded frame.
Definition dbc_decoder.h:51
const DecodeFrame * definition
Definition dbc_decoder.h:52
One decoded signal value.
Definition dbc_decoder.h:37
std::variant< std::int64_t, std::uint64_t > rawValue
Definition dbc_decoder.h:39
const DecodeSignal * definition
Definition dbc_decoder.h:38
Key for fast frame lookup.
Raw CAN frame used for runtime or trace decoding.
Definition dbc_decoder.h:24
std::vector< std::uint8_t > data
Definition dbc_decoder.h:27
std::uint32_t canId
Definition dbc_decoder.h:25
bool isExtended
Definition dbc_decoder.h:26