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