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 "j1939.h"
14#include "signal_layout.h"
15#include <cmath>
16#include <stdexcept>
17#include <unordered_set>
18#include <utility>
19
20std::shared_ptr<const DecodeFrame> DbcDecoder::FindFrame(const DecodeDatabase &database,
21 std::uint32_t canId,
22 bool isExtended) const {
23 return ResolveFrame(database, canId, isExtended).definition;
24}
25
26PgnLookupResult DbcDecoder::ResolveFrame(const DecodeDatabase &database,
27 std::uint32_t canId, bool isExtended) {
28 const std::shared_ptr<const DecodeFrame> exact = database.FindFrame(FrameKey(canId, isExtended));
29 if (exact)
30 return {exact, false};
31 if (!isExtended || canId > 0x1FFFFFFFU)
32 return {};
33 return database.FindFrameByPgn(ExtractJ1939Pgn(canId));
34}
35
37 const RawCanFrame &frame) const {
38 return DecodeImpl(database, frame, nullptr);
39}
40
42 const RawCanFrame &frame,
43 const std::vector<SignalKey> &selection) const {
44 return DecodeImpl(database, frame, &selection);
45}
46
47DecodedFrameValue DbcDecoder::DecodeImpl(const DecodeDatabase &database,
48 const RawCanFrame &frame,
49 const std::vector<SignalKey> *selection) const {
50 DecodedFrameValue result;
51 result.key = FrameKey(frame.canId, frame.isExtended);
52 const PgnLookupResult match = ResolveFrame(database, frame.canId, frame.isExtended);
53 if (match.ambiguous) {
54 result.status = FrameDecodeStatus::AmbiguousFrame;
55 return result;
56 }
57 const std::shared_ptr<const DecodeFrame> definition = match.definition;
58 if (definition == nullptr)
59 return result;
60 result.key = definition->GetKey();
61
62 std::vector<const DecodeSignal *> selected;
63 if (selection != nullptr) {
64 selected.reserve(selection->size());
65 std::unordered_set<SignalKey, SignalKeyHasher> keys;
66 for (const SignalKey &key: *selection) {
67 if (!(key.frame == result.key))
68 throw std::invalid_argument("Selected signal belongs to another frame: " + key.name);
69 if (!keys.insert(key).second)
70 throw std::invalid_argument("Duplicate selected signal: " + key.name);
71 const std::shared_ptr<const DecodeSignal> signal = database.FindSignal(key);
72 if (!signal)
73 throw std::invalid_argument("Unknown selected signal: " + key.name);
74 selected.push_back(signal.get());
75 }
76 }
77
78 result.definition = definition;
79 result.valid = true;
80 result.status = frame.data.size() < definition->dlc
81 ? FrameDecodeStatus::InsufficientPayload
82 : FrameDecodeStatus::Valid;
83
84 const SelectorState selector = ReadSelector(*definition, frame);
85 const std::size_t count = selection != nullptr ? selected.size() : definition->signals.size();
86 result.signals.reserve(count);
87 for (std::size_t index = 0U; index < count; ++index) {
88 const DecodeSignal &signal = selection != nullptr ? *selected[index] : definition->signals[index];
89 DecodedSignalValue decoded = DecodeOneSignal(signal, definition->dlc, frame, selector);
90 if (!decoded.valid && decoded.status != SignalDecodeStatus::Inactive &&
91 result.status == FrameDecodeStatus::Valid)
92 result.status = FrameDecodeStatus::SignalErrors;
93 decoded.definition = std::shared_ptr<const DecodeSignal>(definition, &signal);
94 decoded.key = SignalKey(result.key, signal.name);
95 result.signals.push_back(std::move(decoded));
96 }
97
98 return result;
99}
100
101bool DbcDecoder::IsValidDefinition(const DecodeSignal &signal, std::uint8_t dlc) {
102 if ((signal.byteOrder != ByteOrder::Intel && signal.byteOrder != ByteOrder::Motorola) ||
103 (signal.valueType != ValueType::Unsigned && signal.valueType != ValueType::Signed) ||
104 (signal.multiplexing.role != MultiplexRole::Unconditional &&
105 signal.multiplexing.role != MultiplexRole::Selector &&
106 signal.multiplexing.role != MultiplexRole::Branch))
107 return false;
108
109 return IsValidSignalLayout(signal.startBit, signal.length,
110 signal.byteOrder == ByteOrder::Intel, dlc);
111}
112
113DbcDecoder::SelectorState DbcDecoder::ReadSelector(const DecodeFrame &definition,
114 const RawCanFrame &frame) {
115 SelectorState selector;
116 std::size_t count = 0U;
117 for (const DecodeSignal &signal: definition.signals) {
118 if (signal.multiplexing.role == MultiplexRole::Selector) {
119 selector.definition = &signal;
120 ++count;
121 }
122 }
123 if (count != 1U)
124 return selector;
125
126 const DecodeSignal &signal = *selector.definition;
127 selector.valid = signal.valueType == ValueType::Unsigned &&
128 IsValidDefinition(signal, definition.dlc);
129 selector.available = selector.valid && ExtractUnsigned(frame.data, signal, selector.value);
130 return selector;
131}
132
133DecodedSignalValue DbcDecoder::DecodeOneSignal(const DecodeSignal &signal,
134 std::uint8_t dlc,
135 const RawCanFrame &frame,
136 const SelectorState &selector) {
137 DecodedSignalValue decoded;
138 std::uint64_t unsignedValue = 0U;
139
140 if (!IsValidDefinition(signal, dlc) ||
141 (signal.multiplexing.role != MultiplexRole::Unconditional && !selector.valid)) {
142 return decoded;
143 }
144 if (signal.multiplexing.role == MultiplexRole::Branch) {
145 if (selector.definition->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector.definition->length)) {
146 return decoded;
147 }
148 if (!selector.available) {
149 decoded.status = SignalDecodeStatus::SelectorUnavailable;
150 return decoded;
151 }
152 if (signal.multiplexing.value != selector.value) {
153 decoded.status = SignalDecodeStatus::Inactive;
154 return decoded;
155 }
156 }
157 if (!ExtractUnsigned(frame.data, signal, unsignedValue)) {
158 decoded.status = SignalDecodeStatus::InsufficientPayload;
159 return decoded;
160 }
161
162 if (signal.valueType == ValueType::Signed)
163 decoded.rawValue = SignExtend(unsignedValue, signal.length);
164 else
165 decoded.rawValue = unsignedValue;
166
167 double numericValue;
168 if (const std::int64_t *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
169 numericValue = static_cast<double>(*signedValue);
170 else
171 numericValue = static_cast<double>(std::get<std::uint64_t>(decoded.rawValue));
172 decoded.physicalValue = numericValue * signal.factor + signal.offset;
173 if (!std::isfinite(decoded.physicalValue)) {
174 decoded.status = SignalDecodeStatus::PhysicalConversionFailed;
175 return decoded;
176 }
177 decoded.valid = true;
178 decoded.status = SignalDecodeStatus::Valid;
179
180 return decoded;
181}
182
183bool DbcDecoder::ExtractUnsigned(const std::vector<std::uint8_t> &data,
184 const DecodeSignal &signal,
185 std::uint64_t &value) {
186 if ((signal.length == 0U) || (signal.length > 64U))
187 return false;
188
189 if (signal.byteOrder == ByteOrder::Intel)
190 return ExtractIntel(data, signal.startBit, signal.length, value);
191
192 return ExtractMotorola(data, signal.startBit, signal.length, value);
193}
194
195bool 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 value = 0U;
200
201 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
202 const std::uint64_t absoluteBit = std::uint64_t(startBit) + bitIndex;
203 const std::uint64_t byteIndex = absoluteBit / 8U;
204 const std::uint32_t bitInByte = absoluteBit % 8U;
205
206 if (byteIndex >= data.size())
207 return false;
208
209 const std::uint64_t bitValue =
210 (static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
211
212 value |= bitValue;
213 }
214
215 return true;
216}
217
218bool 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 value = 0U;
231
232 std::size_t byteIndex = startBit / 8U;
233 std::uint32_t bitInByte = startBit % 8U;
234
235 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
236 if (byteIndex >= data.size())
237 return false;
238
239 value <<= 1U;
240 value |= static_cast<std::uint64_t>((data[byteIndex] >> bitInByte) & 0x01U);
241
242 if (bitInByte == 0U) {
243 ++byteIndex;
244 bitInByte = 7U;
245 } else
246 --bitInByte;
247 }
248
249 return true;
250}
251
252std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
253 if ((bitLength == 0U) || (bitLength > 64U))
254 return 0;
255
256 const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
257 const std::uint64_t valueMask = (bitLength == 64U)
258 ? ~std::uint64_t(0U)
259 : (std::uint64_t(1U) << bitLength) - 1U;
260 value &= valueMask;
261
262 if ((value & signMask) == 0U)
263 return static_cast<std::int64_t>(value);
264
265 // The complemented magnitude fits int64_t, including for INT64_MIN.
266 return -1 - static_cast<std::int64_t>((~value) & valueMask);
267}
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 exact CAN ID first, then unique PGN among explicitly J1939 definitions.
Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
Return an owning signal handle, or an empty handle for a missing key.
std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
CAN frame decoding API and result types.
Runtime-ready frame definition.
std::uint8_t dlc
Runtime-ready signal definition.
std::string name
ValueType valueType
std::uint32_t startBit
ByteOrder byteOrder
std::uint32_t length
Multiplexing multiplexing
Fully decoded frame.
Definition dbc_decoder.h:73
std::shared_ptr< const DecodeFrame > definition
Definition dbc_decoder.h:74
FrameDecodeStatus status
Definition dbc_decoder.h:78
One decoded signal value.
Definition dbc_decoder.h:54
RawSignalValue rawValue
Definition dbc_decoder.h:57
std::shared_ptr< const DecodeSignal > definition
Definition dbc_decoder.h:55
SignalDecodeStatus status
Definition dbc_decoder.h:60
Stable frame identifier: normalized CAN ID and frame type.
MultiplexRole role
std::uint64_t value
std::shared_ptr< const DecodeFrame > definition
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