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#include <cmath>
14#include <utility>
15
16std::shared_ptr<const DecodeFrame> DbcDecoder::FindFrame(const DecodeDatabase &database,
17 std::uint32_t canId,
18 bool isExtended) const {
19 return database.FindFrame(FrameKey(canId, isExtended));
20}
21
23 const RawCanFrame &frame) const {
24 DecodedFrameValue result;
25 result.key = FrameKey(frame.canId, frame.isExtended);
26 const std::shared_ptr<const DecodeFrame> definition = FindFrame(database, frame.canId, frame.isExtended);
27
28 if (definition == nullptr)
29 return result;
30
31 result.definition = definition;
32 result.valid = true;
33 result.status = frame.data.size() < definition->dlc
34 ? FrameDecodeStatus::InsufficientPayload
35 : FrameDecodeStatus::Valid;
36
37 const SelectorState selector = ReadSelector(*definition, frame);
38 result.signals.reserve(definition->signals.size());
39 for (const DecodeSignal &signal: definition->signals) {
40 DecodedSignalValue decoded = DecodeOneSignal(signal, definition->dlc, frame, selector);
41 if (!decoded.valid && decoded.status != SignalDecodeStatus::Inactive &&
42 result.status == FrameDecodeStatus::Valid)
43 result.status = FrameDecodeStatus::SignalErrors;
44 decoded.definition = std::shared_ptr<const DecodeSignal>(definition, &signal);
45 decoded.key = SignalKey(result.key, signal.name);
46 result.signals.push_back(std::move(decoded));
47 }
48
49 return result;
50}
51
52bool DbcDecoder::IsValidDefinition(const DecodeSignal &signal, std::uint8_t dlc) {
53 if (signal.length == 0U || signal.length > 64U ||
54 (signal.byteOrder != ByteOrder::Intel && signal.byteOrder != ByteOrder::Motorola) ||
55 (signal.valueType != ValueType::Unsigned && signal.valueType != ValueType::Signed) ||
56 (signal.multiplexing.role != MultiplexRole::Unconditional &&
57 signal.multiplexing.role != MultiplexRole::Selector &&
58 signal.multiplexing.role != MultiplexRole::Branch))
59 return false;
60
61 // Use widened coordinates to avoid overflow on malformed start bits.
62 const std::uint64_t start = signal.byteOrder == ByteOrder::Intel
63 ? signal.startBit
64 : std::uint64_t(signal.startBit / 8U) * 8U + 7U - signal.startBit % 8U;
65 return start + signal.length <= std::uint64_t(dlc) * 8U;
66}
67
68DbcDecoder::SelectorState DbcDecoder::ReadSelector(const DecodeFrame &definition,
69 const RawCanFrame &frame) {
70 SelectorState selector;
71 std::size_t count = 0U;
72 for (const DecodeSignal &signal: definition.signals) {
73 if (signal.multiplexing.role == MultiplexRole::Selector) {
74 selector.definition = &signal;
75 ++count;
76 }
77 }
78 if (count != 1U)
79 return selector;
80
81 const DecodeSignal &signal = *selector.definition;
82 selector.valid = signal.valueType == ValueType::Unsigned &&
83 IsValidDefinition(signal, definition.dlc);
84 selector.available = selector.valid && ExtractUnsigned(frame.data, signal, selector.value);
85 return selector;
86}
87
88DecodedSignalValue DbcDecoder::DecodeOneSignal(const DecodeSignal &signal,
89 std::uint8_t dlc,
90 const RawCanFrame &frame,
91 const SelectorState &selector) {
92 DecodedSignalValue decoded;
93 std::uint64_t unsignedValue = 0U;
94
95 if (!IsValidDefinition(signal, dlc) ||
96 (signal.multiplexing.role != MultiplexRole::Unconditional && !selector.valid)) {
97 return decoded;
98 }
99 if (signal.multiplexing.role == MultiplexRole::Branch) {
100 if (selector.definition->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector.definition->length)) {
101 return decoded;
102 }
103 if (!selector.available) {
104 decoded.status = SignalDecodeStatus::SelectorUnavailable;
105 return decoded;
106 }
107 if (signal.multiplexing.value != selector.value) {
108 decoded.status = SignalDecodeStatus::Inactive;
109 return decoded;
110 }
111 }
112 if (!ExtractUnsigned(frame.data, signal, unsignedValue)) {
113 decoded.status = SignalDecodeStatus::InsufficientPayload;
114 return decoded;
115 }
116
117 if (signal.valueType == ValueType::Signed)
118 decoded.rawValue = SignExtend(unsignedValue, signal.length);
119 else
120 decoded.rawValue = unsignedValue;
121
122 double numericValue;
123 if (const std::int64_t *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
124 numericValue = static_cast<double>(*signedValue);
125 else
126 numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
127 decoded.physicalValue = numericValue * signal.factor + signal.offset;
128 if (!std::isfinite(decoded.physicalValue)) {
129 decoded.status = SignalDecodeStatus::PhysicalConversionFailed;
130 return decoded;
131 }
132 decoded.valid = true;
133 decoded.status = SignalDecodeStatus::Valid;
134
135 return decoded;
136}
137
138bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
139 const DecodeSignal &signal,
140 std::uint64_t &value) {
141 if ((signal.length == 0U) || (signal.length > 64U))
142 return false;
143
144 if (signal.byteOrder == ByteOrder::Intel)
145 return ExtractIntel(data, signal.startBit, signal.length, value);
146
147 return ExtractMotorola(data, signal.startBit, signal.length, value);
148}
149
150bool DbcDecoder::ExtractIntel(const std::vector<std::uint8_t> &data,
151 std::uint32_t startBit,
152 std::uint32_t length,
153 std::uint64_t &value) {
154 value = 0U;
155
156 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
157 const std::uint32_t absoluteBit = startBit + bitIndex;
158 const std::uint32_t byteIndex = absoluteBit / 8U;
159 const std::uint32_t bitInByte = absoluteBit % 8U;
160
161 if (byteIndex >= data.size())
162 return false;
163
164 const std::uint64_t bitValue =
165 (static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
166
167 value |= bitValue;
168 }
169
170 return true;
171}
172
173bool DbcDecoder::ExtractMotorola(const std::vector<std::uint8_t> &data,
174 std::uint32_t startBit,
175 std::uint32_t length,
176 std::uint64_t &value) {
177 /*
178 * DBC Motorola bit numbering:
179 * - startBit points to the most significant bit of the signal
180 * - inside a byte, bit numbering goes 7..0
181 * - crossing byte boundary moves to the next byte, bit 7
182 * Example: a signal starting at 7 follows 7..0, 15..8, 23..16.
183 */
184
185 value = 0U;
186
187 std::size_t byteIndex = startBit / 8U;
188 std::uint32_t bitInByte = startBit % 8U;
189
190 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
191 if (byteIndex >= data.size())
192 return false;
193
194 value <<= 1U;
195 value |= static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U);
196
197 if (bitInByte == 0U) {
198 ++byteIndex;
199 bitInByte = 7U;
200 } else
201 --bitInByte;
202 }
203
204 return true;
205}
206
207std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
208 if ((bitLength == 0U) || (bitLength > 64U))
209 return 0;
210
211 const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
212 const std::uint64_t valueMask = (bitLength == 64U)
213 ? ~std::uint64_t(0U)
214 : (std::uint64_t(1U) << bitLength) - 1U;
215 value &= valueMask;
216
217 if ((value & signMask) == 0U)
218 return static_cast<std::int64_t>(value);
219
220 // The complemented magnitude fits int64_t, including for INT64_MIN.
221 return -1 - static_cast<std::int64_t>((~value) & valueMask);
222}
DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
Decode one raw CAN frame.
std::shared_ptr< const DecodeFrame > FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const
Find frame definition by CAN ID.
Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
Runtime-ready frame definition.
std::uint8_t dlc
Runtime-ready signal definition.
ValueType valueType
std::uint32_t startBit
ByteOrder byteOrder
std::uint32_t length
Fully decoded frame.
Definition dbc_decoder.h:71
std::shared_ptr< const DecodeFrame > definition
Definition dbc_decoder.h:72
FrameDecodeStatus status
Definition dbc_decoder.h:76
One decoded signal value.
Definition dbc_decoder.h:52
RawSignalValue rawValue
Definition dbc_decoder.h:55
std::shared_ptr< const DecodeSignal > definition
Definition dbc_decoder.h:53
Stable frame identifier: normalized CAN ID and frame type.
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