Branch data Line data Source code
1 : : /**
2 : : * @file dbc_decoder.cpp
3 : : * @brief CAN signal extraction and physical value conversion.
4 : : *
5 : : * Created: 2026-03-13
6 : : * Author: Deeaitch (Dim. Himro)
7 : : *
8 : : * Licensed under the MIT License.
9 : : * See LICENSE file in the project root for full license text.
10 : : */
11 : :
12 : : #include "dbc_decoder.h"
13 : : #include "j1939.h"
14 : : #include "signal_layout.h"
15 : : #include <cmath>
16 : : #include <stdexcept>
17 : : #include <unordered_set>
18 : : #include <utility>
19 : :
20 : 32 : std::shared_ptr<const DecodeFrame> DbcDecoder::FindFrame(const DecodeDatabase &database,
21 : : std::uint32_t canId,
22 : : bool isExtended) const {
23 [ + - ]: 32 : return ResolveFrame(database, canId, isExtended).definition;
24 : : }
25 : :
26 : 6440 : PgnLookupResult DbcDecoder::ResolveFrame(const DecodeDatabase &database,
27 : : std::uint32_t canId, bool isExtended) {
28 [ + - ]: 6440 : const std::shared_ptr<const DecodeFrame> exact = database.FindFrame(FrameKey(canId, isExtended));
29 [ + + ]: 6440 : if (exact)
30 : 6335 : return {exact, false};
31 [ + + + + ]: 105 : if (!isExtended || canId > 0x1FFFFFFFU)
32 : 25 : return {};
33 [ + - ]: 80 : return database.FindFrameByPgn(ExtractJ1939Pgn(canId));
34 : 6440 : }
35 : :
36 : 6396 : DecodedFrameValue DbcDecoder::Decode(const DecodeDatabase &database,
37 : : const RawCanFrame &frame) const {
38 : 6396 : return DecodeImpl(database, frame, nullptr);
39 : : }
40 : :
41 : 12 : DecodedFrameValue DbcDecoder::Decode(const DecodeDatabase &database,
42 : : const RawCanFrame &frame,
43 : : const std::vector<SignalKey> &selection) const {
44 : 12 : return DecodeImpl(database, frame, &selection);
45 : : }
46 : :
47 : 6408 : DecodedFrameValue DbcDecoder::DecodeImpl(const DecodeDatabase &database,
48 : : const RawCanFrame &frame,
49 : : const std::vector<SignalKey> *selection) const {
50 : 6408 : DecodedFrameValue result;
51 : 6408 : result.key = FrameKey(frame.canId, frame.isExtended);
52 [ + - ]: 6408 : const PgnLookupResult match = ResolveFrame(database, frame.canId, frame.isExtended);
53 [ + + ]: 6408 : if (match.ambiguous) {
54 : 8 : result.status = FrameDecodeStatus::AmbiguousFrame;
55 : 8 : return result;
56 : : }
57 : 6400 : const std::shared_ptr<const DecodeFrame> definition = match.definition;
58 [ + + ]: 6400 : if (definition == nullptr)
59 : 55 : return result;
60 : 6345 : result.key = definition->GetKey();
61 : :
62 : 6345 : std::vector<const DecodeSignal *> selected;
63 [ + + ]: 6345 : if (selection != nullptr) {
64 [ + - ]: 8 : selected.reserve(selection->size());
65 : 8 : std::unordered_set<SignalKey, SignalKeyHasher> keys;
66 [ + + ]: 12 : for (const SignalKey &key: *selection) {
67 [ + + ]: 8 : if (!(key.frame == result.key))
68 [ + - + - ]: 4 : throw std::invalid_argument("Selected signal belongs to another frame: " + key.name);
69 [ + - - + ]: 4 : if (!keys.insert(key).second)
70 [ # # # # ]: 0 : throw std::invalid_argument("Duplicate selected signal: " + key.name);
71 [ + - ]: 4 : const std::shared_ptr<const DecodeSignal> signal = database.FindSignal(key);
72 [ - + ]: 4 : if (!signal)
73 [ # # # # ]: 0 : throw std::invalid_argument("Unknown selected signal: " + key.name);
74 [ + - ]: 4 : selected.push_back(signal.get());
75 : 4 : }
76 : 8 : }
77 : :
78 : 6341 : result.definition = definition;
79 : 6341 : result.valid = true;
80 : 6341 : result.status = frame.data.size() < definition->dlc
81 [ + + ]: 6341 : ? FrameDecodeStatus::InsufficientPayload
82 : : : FrameDecodeStatus::Valid;
83 : :
84 [ + - ]: 6341 : const SelectorState selector = ReadSelector(*definition, frame);
85 [ + + ]: 6341 : const std::size_t count = selection != nullptr ? selected.size() : definition->signals.size();
86 [ + - ]: 6341 : result.signals.reserve(count);
87 [ + + ]: 12716 : for (std::size_t index = 0U; index < count; ++index) {
88 [ + + ]: 6375 : const DecodeSignal &signal = selection != nullptr ? *selected[index] : definition->signals[index];
89 [ + - ]: 6375 : DecodedSignalValue decoded = DecodeOneSignal(signal, definition->dlc, frame, selector);
90 [ + + + + ]: 6375 : if (!decoded.valid && decoded.status != SignalDecodeStatus::Inactive &&
91 [ + + ]: 31 : result.status == FrameDecodeStatus::Valid)
92 : 5 : result.status = FrameDecodeStatus::SignalErrors;
93 : 6375 : decoded.definition = std::shared_ptr<const DecodeSignal>(definition, &signal);
94 [ + - ]: 6375 : decoded.key = SignalKey(result.key, signal.name);
95 [ + - ]: 6375 : result.signals.push_back(std::move(decoded));
96 : 6375 : }
97 : :
98 : 6341 : return result;
99 : 6420 : }
100 : :
101 : 6396 : bool DbcDecoder::IsValidDefinition(const DecodeSignal &signal, std::uint8_t dlc) {
102 [ + + + - ]: 6396 : if ((signal.byteOrder != ByteOrder::Intel && signal.byteOrder != ByteOrder::Motorola) ||
103 [ + + + - ]: 6396 : (signal.valueType != ValueType::Unsigned && signal.valueType != ValueType::Signed) ||
104 [ + + ]: 6396 : (signal.multiplexing.role != MultiplexRole::Unconditional &&
105 [ + + ]: 71 : signal.multiplexing.role != MultiplexRole::Selector &&
106 [ - + ]: 29 : signal.multiplexing.role != MultiplexRole::Branch))
107 : 0 : return false;
108 : :
109 : 6396 : return IsValidSignalLayout(signal.startBit, signal.length,
110 : 6396 : signal.byteOrder == ByteOrder::Intel, dlc);
111 : : }
112 : :
113 : 6341 : DbcDecoder::SelectorState DbcDecoder::ReadSelector(const DecodeFrame &definition,
114 : : const RawCanFrame &frame) {
115 : 6341 : SelectorState selector;
116 : 6341 : std::size_t count = 0U;
117 [ + + ]: 12716 : for (const DecodeSignal &signal: definition.signals) {
118 [ + + ]: 6375 : if (signal.multiplexing.role == MultiplexRole::Selector) {
119 : 21 : selector.definition = &signal;
120 : 21 : ++count;
121 : : }
122 : : }
123 [ + + ]: 6341 : if (count != 1U)
124 : 6320 : return selector;
125 : :
126 : 21 : const DecodeSignal &signal = *selector.definition;
127 [ + - ]: 42 : selector.valid = signal.valueType == ValueType::Unsigned &&
128 [ + - ]: 21 : IsValidDefinition(signal, definition.dlc);
129 [ + - + + ]: 21 : selector.available = selector.valid && ExtractUnsigned(frame.data, signal, selector.value);
130 : 21 : return selector;
131 : : }
132 : :
133 : 6375 : DecodedSignalValue DbcDecoder::DecodeOneSignal(const DecodeSignal &signal,
134 : : std::uint8_t dlc,
135 : : const RawCanFrame &frame,
136 : : const SelectorState &selector) {
137 : 6375 : DecodedSignalValue decoded;
138 : 6375 : std::uint64_t unsignedValue = 0U;
139 : :
140 [ + - + - : 12750 : if (!IsValidDefinition(signal, dlc) ||
- + ]
141 [ + + - + ]: 6375 : (signal.multiplexing.role != MultiplexRole::Unconditional && !selector.valid)) {
142 : 0 : return decoded;
143 : : }
144 [ + + ]: 6375 : if (signal.multiplexing.role == MultiplexRole::Branch) {
145 [ + + - + ]: 29 : if (selector.definition->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector.definition->length)) {
146 : 0 : return decoded;
147 : : }
148 [ + + ]: 29 : if (!selector.available) {
149 : 3 : decoded.status = SignalDecodeStatus::SelectorUnavailable;
150 : 3 : return decoded;
151 : : }
152 [ + + ]: 26 : if (signal.multiplexing.value != selector.value) {
153 : 13 : decoded.status = SignalDecodeStatus::Inactive;
154 : 13 : return decoded;
155 : : }
156 : : }
157 [ + - + + ]: 6359 : if (!ExtractUnsigned(frame.data, signal, unsignedValue)) {
158 : 23 : decoded.status = SignalDecodeStatus::InsufficientPayload;
159 : 23 : return decoded;
160 : : }
161 : :
162 [ + + ]: 6336 : if (signal.valueType == ValueType::Signed)
163 [ + - ]: 81 : decoded.rawValue = SignExtend(unsignedValue, signal.length);
164 : : else
165 : 6255 : decoded.rawValue = unsignedValue;
166 : :
167 : : double numericValue;
168 [ + + ]: 6336 : if (const std::int64_t *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
169 : 81 : numericValue = static_cast<double>(*signedValue);
170 : : else
171 [ + - ]: 6255 : numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
172 : 6336 : decoded.physicalValue = numericValue * signal.factor + signal.offset;
173 [ + + ]: 6336 : if (!std::isfinite(decoded.physicalValue)) {
174 : 5 : decoded.status = SignalDecodeStatus::PhysicalConversionFailed;
175 : 5 : return decoded;
176 : : }
177 : 6331 : decoded.valid = true;
178 : 6331 : decoded.status = SignalDecodeStatus::Valid;
179 : :
180 : 6331 : return decoded;
181 : 0 : }
182 : :
183 : 6380 : bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
184 : : const DecodeSignal &signal,
185 : : std::uint64_t &value) {
186 [ + - - + ]: 6380 : if ((signal.length == 0U) || (signal.length > 64U))
187 : 0 : return false;
188 : :
189 [ + + ]: 6380 : if (signal.byteOrder == ByteOrder::Intel)
190 : 3242 : return ExtractIntel(data, signal.startBit, signal.length, value);
191 : :
192 : 3138 : return ExtractMotorola(data, signal.startBit, signal.length, value);
193 : : }
194 : :
195 : 3242 : bool DbcDecoder::ExtractIntel(const std::vector<std::uint8_t> &data,
196 : : std::uint32_t startBit,
197 : : std::uint32_t length,
198 : : std::uint64_t &value) {
199 : 3242 : value = 0U;
200 : :
201 [ + + ]: 105558 : for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
202 : 102334 : const std::uint64_t absoluteBit = std::uint64_t(startBit) + bitIndex;
203 : 102334 : const std::uint64_t byteIndex = absoluteBit / 8U;
204 : 102334 : const std::uint32_t bitInByte = absoluteBit % 8U;
205 : :
206 [ + + ]: 102334 : if (byteIndex >= data.size())
207 : 18 : return false;
208 : :
209 : : const std::uint64_t bitValue =
210 : 102316 : (static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
211 : :
212 : 102316 : value |= bitValue;
213 : : }
214 : :
215 : 3224 : return true;
216 : : }
217 : :
218 : 3138 : bool DbcDecoder::ExtractMotorola(const std::vector<std::uint8_t> &data,
219 : : std::uint32_t startBit,
220 : : std::uint32_t length,
221 : : std::uint64_t &value) {
222 : : /*
223 : : * DBC Motorola bit numbering:
224 : : * - startBit points to the most significant bit of the signal
225 : : * - inside a byte, bit numbering goes 7..0
226 : : * - crossing byte boundary moves to the next byte, bit 7
227 : : * Example: a signal starting at 7 follows 7..0, 15..8, 23..16.
228 : : */
229 : :
230 : 3138 : value = 0U;
231 : :
232 : 3138 : std::size_t byteIndex = startBit / 8U;
233 : 3138 : std::uint32_t bitInByte = startBit % 8U;
234 : :
235 [ + + ]: 104732 : for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
236 [ + + ]: 101601 : if (byteIndex >= data.size())
237 : 7 : return false;
238 : :
239 : 101594 : value <<= 1U;
240 : 101594 : value |= static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U);
241 : :
242 [ + + ]: 101594 : if (bitInByte == 0U) {
243 : 12688 : ++byteIndex;
244 : 12688 : bitInByte = 7U;
245 : : } else
246 : 88906 : --bitInByte;
247 : : }
248 : :
249 : 3131 : return true;
250 : : }
251 : :
252 : 81 : std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
253 [ + - - + ]: 81 : if ((bitLength == 0U) || (bitLength > 64U))
254 : 0 : return 0;
255 : :
256 : 81 : const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
257 : 81 : const std::uint64_t valueMask = (bitLength == 64U)
258 [ + + ]: 81 : ? ~std::uint64_t(0U)
259 : 68 : : (std::uint64_t(1U) << bitLength) - 1U;
260 : 81 : value &= valueMask;
261 : :
262 [ + + ]: 81 : if ((value & signMask) == 0U)
263 : 41 : return static_cast<std::int64_t>(value);
264 : :
265 : : // The complemented magnitude fits int64_t, including for INT64_MIN.
266 : 40 : return -1 - static_cast<std::int64_t>((~value) & valueMask);
267 : : }
|