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 const SelectorState selector = ReadSelector(*definition, frame);
43 for (const DecodeSignal &signal : definition->signals)
44 result.signals.push_back(DecodeOneSignal(signal, frame, selector));
45
46 return result;
47}
48
49DbcDecoder::SelectorState DbcDecoder::ReadSelector(const DecodeFrame &definition,
50 const RawCanFrame &frame) {
51 SelectorState selector;
52 std::size_t count = 0U;
53 for (const DecodeSignal &signal : definition.signals) {
54 if (signal.multiplexing.role == MultiplexRole::Selector) {
55 selector.definition = &signal;
56 ++count;
57 }
58 }
59 if (count != 1U)
60 return selector;
61
62 const DecodeSignal &signal = *selector.definition;
63 selector.valid = signal.valueType == ValueType::Unsigned &&
64 signal.length > 0U && signal.length <= 64U;
65 selector.available = selector.valid && ExtractUnsigned(frame.data, signal, selector.value);
66 return selector;
67}
68
69DecodedSignalValue DbcDecoder::DecodeOneSignal(const DecodeSignal &signal,
70 const RawCanFrame &frame,
71 const SelectorState &selector) {
72 DecodedSignalValue decoded;
73 std::uint64_t unsignedValue = 0U;
74
75 decoded.definition = &signal;
76
77 if (signal.length == 0U || signal.length > 64U ||
78 (signal.multiplexing.role != MultiplexRole::Unconditional && !selector.valid)) {
79 return decoded;
80 }
81 if (signal.multiplexing.role == MultiplexRole::Branch) {
82 if (selector.definition->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector.definition->length)) {
83 return decoded;
84 }
85 if (!selector.available) {
86 decoded.status = SignalDecodeStatus::SelectorUnavailable;
87 return decoded;
88 }
89 if (signal.multiplexing.value != selector.value) {
90 decoded.status = SignalDecodeStatus::Inactive;
91 return decoded;
92 }
93 }
94 if (!ExtractUnsigned(frame.data, signal, unsignedValue)) {
95 decoded.status = SignalDecodeStatus::InsufficientPayload;
96 return decoded;
97 }
98
99 if (signal.valueType == ValueType::Signed)
100 decoded.rawValue = SignExtend(unsignedValue, signal.length);
101 else
102 decoded.rawValue = unsignedValue;
103
104 double numericValue;
105 if (const std::int64_t *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
106 numericValue = static_cast<double>(*signedValue);
107 else
108 numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
109 decoded.physicalValue = numericValue * signal.factor + signal.offset;
110 decoded.valid = true;
111 decoded.status = SignalDecodeStatus::Valid;
112
113 return decoded;
114}
115
116bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
117 const DecodeSignal &signal,
118 std::uint64_t &value) {
119 if ((signal.length == 0U) || (signal.length > 64U))
120 return false;
121
122 if (signal.byteOrder == ByteOrder::Intel)
123 return ExtractIntel(data, signal.startBit, signal.length, value);
124
125 return ExtractMotorola(data, signal.startBit, signal.length, value);
126}
127
128bool DbcDecoder::ExtractIntel(const std::vector<std::uint8_t> &data,
129 std::uint32_t startBit,
130 std::uint32_t length,
131 std::uint64_t &value) {
132 value = 0U;
133
134 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
135 const std::uint32_t absoluteBit = startBit + bitIndex;
136 const std::uint32_t byteIndex = absoluteBit / 8U;
137 const std::uint32_t bitInByte = absoluteBit % 8U;
138
139 if (byteIndex >= data.size())
140 return false;
141
142 const std::uint64_t bitValue =
143 (static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
144
145 value |= bitValue;
146 }
147
148 return true;
149}
150
151bool DbcDecoder::ExtractMotorola(const std::vector<std::uint8_t> &data,
152 std::uint32_t startBit,
153 std::uint32_t length,
154 std::uint64_t &value) {
155 /*
156 * DBC Motorola bit numbering:
157 * - startBit points to the most significant bit of the signal
158 * - inside a byte, bit numbering goes 7..0
159 * - crossing byte boundary moves to the next byte, bit 7
160 * Example: a signal starting at 7 follows 7..0, 15..8, 23..16.
161 */
162
163 value = 0U;
164
165 std::size_t byteIndex = startBit / 8U;
166 std::uint32_t bitInByte = startBit % 8U;
167
168 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
169 if (byteIndex >= data.size())
170 return false;
171
172 value <<= 1U;
173 value |= static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U);
174
175 if (bitInByte == 0U) {
176 ++byteIndex;
177 bitInByte = 7U;
178 } else
179 --bitInByte;
180 }
181
182 return true;
183}
184
185std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
186 if ((bitLength == 0U) || (bitLength > 64U))
187 return 0;
188
189 const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
190 const std::uint64_t valueMask = (bitLength == 64U)
191 ? ~std::uint64_t(0U)
192 : (std::uint64_t(1U) << bitLength) - 1U;
193 value &= valueMask;
194
195 if ((value & signMask) == 0U)
196 return static_cast<std::int64_t>(value);
197
198 // The complemented magnitude fits int64_t, including for INT64_MIN.
199 return -1 - static_cast<std::int64_t>((~value) & valueMask);
200}
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:61
const DecodeFrame * definition
Definition dbc_decoder.h:62
One decoded signal value.
Definition dbc_decoder.h:43
RawSignalValue rawValue
Definition dbc_decoder.h:45
const DecodeSignal * definition
Definition dbc_decoder.h:44
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