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