14#include "signal_layout.h"
17#include <unordered_set>
22 bool isExtended)
const {
23 return ResolveFrame(database, canId, isExtended).
definition;
27 std::uint32_t canId,
bool isExtended) {
28 const std::shared_ptr<const DecodeFrame> exact = database.
FindFrame(
FrameKey(canId, isExtended));
30 return {exact,
false};
31 if (!isExtended || canId > 0x1FFFFFFFU)
38 return DecodeImpl(database, frame,
nullptr);
43 const std::vector<SignalKey> &selection)
const {
44 return DecodeImpl(database, frame, &selection);
49 const std::vector<SignalKey> *selection)
const {
54 result.
status = FrameDecodeStatus::AmbiguousFrame;
57 const std::shared_ptr<const DecodeFrame> definition = match.
definition;
58 if (definition ==
nullptr)
60 result.
key = definition->GetKey();
62 std::vector<const DecodeSignal *> selected;
63 if (selection !=
nullptr) {
64 selected.reserve(selection->size());
65 std::unordered_set<SignalKey, SignalKeyHasher> keys;
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);
73 throw std::invalid_argument(
"Unknown selected signal: " + key.name);
74 selected.push_back(signal.get());
80 result.
status = frame.
data.size() < definition->dlc
81 ? FrameDecodeStatus::InsufficientPayload
82 : FrameDecodeStatus::Valid;
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 const std::size_t signalIndex =
static_cast<std::size_t
>(&signal - definition->signals.data());
91 ActivationStatus(signalIndex, *definition, frame, graph));
92 if (!decoded.
valid && decoded.
status != SignalDecodeStatus::Inactive &&
93 result.
status == FrameDecodeStatus::Valid)
94 result.
status = FrameDecodeStatus::SignalErrors;
95 decoded.
definition = std::shared_ptr<const DecodeSignal>(definition, &signal);
97 result.signals.push_back(std::move(decoded));
103bool DbcDecoder::IsValidDefinition(
const DecodeSignal &signal, std::uint8_t dlc) {
104 if ((signal.
byteOrder != ByteOrder::Intel && signal.
byteOrder != ByteOrder::Motorola) ||
106 (signal.
multiplexing.role != MultiplexRole::Unconditional &&
109 signal.
multiplexing.role != MultiplexRole::BranchSelector))
113 signal.
byteOrder == ByteOrder::Intel, dlc);
121 std::vector<std::size_t> path;
122 while (graph.parents[index] != definition.signals.size()) {
123 path.push_back(index);
124 index = graph.parents[index];
126 for (std::vector<std::size_t>::const_reverse_iterator it = path.rbegin(); it != path.rend(); ++it) {
127 const DecodeSignal &selector = definition.signals[graph.parents[*it]];
128 std::uint64_t value = 0U;
129 if (!ExtractUnsigned(frame.
data, selector, value))
130 return SignalDecodeStatus::SelectorUnavailable;
131 if (!graph.Matches(*it, value))
132 return SignalDecodeStatus::Inactive;
134 return SignalDecodeStatus::Valid;
142 std::uint64_t unsignedValue = 0U;
144 if (!IsValidDefinition(signal, dlc))
146 if (activation != SignalDecodeStatus::Valid) {
147 decoded.
status = activation;
150 if (!ExtractUnsigned(frame.
data, signal, unsignedValue)) {
151 decoded.
status = SignalDecodeStatus::InsufficientPayload;
155 if (signal.
valueType == ValueType::Signed)
161 if (
const std::int64_t *signedValue = std::get_if<std::int64_t>(&decoded.
rawValue))
162 numericValue =
static_cast<double>(*signedValue);
164 numericValue =
static_cast<double>(std::get<std::uint64_t>(decoded.
rawValue));
167 decoded.
status = SignalDecodeStatus::PhysicalConversionFailed;
170 decoded.
valid =
true;
171 decoded.
status = SignalDecodeStatus::Valid;
176bool DbcDecoder::ExtractUnsigned(
const std::vector<std::uint8_t> &data,
178 std::uint64_t &value) {
182 if (signal.
byteOrder == ByteOrder::Intel)
185 return ExtractMotorola(data, signal.
startBit, signal.
length, value);
188bool DbcDecoder::ExtractIntel(
const std::vector<std::uint8_t> &data,
189 std::uint32_t startBit,
190 std::uint32_t length,
191 std::uint64_t &value) {
194 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
195 const std::uint64_t absoluteBit = std::uint64_t(startBit) + bitIndex;
196 const std::uint64_t byteIndex = absoluteBit / 8U;
197 const std::uint32_t bitInByte = absoluteBit % 8U;
199 if (byteIndex >= data.size())
202 const std::uint64_t bitValue =
203 (
static_cast<std::uint64_t
>((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex);
211bool DbcDecoder::ExtractMotorola(
const std::vector<std::uint8_t> &data,
212 std::uint32_t startBit,
213 std::uint32_t length,
214 std::uint64_t &value) {
225 std::size_t byteIndex = startBit / 8U;
226 std::uint32_t bitInByte = startBit % 8U;
228 for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) {
229 if (byteIndex >= data.size())
233 value |=
static_cast<std::uint64_t
>((data[byteIndex] >> bitInByte) & 0x01U);
235 if (bitInByte == 0U) {
245std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) {
246 if ((bitLength == 0U) || (bitLength > 64U))
249 const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U);
250 const std::uint64_t valueMask = (bitLength == 64U)
252 : (std::uint64_t(1U) << bitLength) - 1U;
255 if ((value & signMask) == 0U)
256 return static_cast<std::int64_t
>(value);
259 return -1 -
static_cast<std::int64_t
>((~value) & valueMask);
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.
SignalDecodeStatus
Outcome of signal extraction and physical conversion.
Runtime-ready frame definition.
Runtime-ready signal definition.
Multiplexing multiplexing
std::shared_ptr< const DecodeFrame > definition
One decoded signal value.
std::shared_ptr< const DecodeSignal > definition
SignalDecodeStatus status
Stable frame identifier: normalized CAN ID and frame type.
std::shared_ptr< const DecodeFrame > definition
Raw CAN frame used for runtime or trace decoding.
std::vector< std::uint8_t > data