/** * @file dbc_decoder.cpp * @brief * * Created: 2026-03-13 * Author: Deeaitch (Dim. Himro) * * Licensed under the MIT License. * See LICENSE file in the project root for full license text. */ #include "dbc_decoder.h" #include "signal_layout.h" #include #include std::shared_ptr DbcDecoder::FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const { return database.FindFrame(FrameKey(canId, isExtended)); } DecodedFrameValue DbcDecoder::Decode(const DecodeDatabase &database, const RawCanFrame &frame) const { DecodedFrameValue result; result.key = FrameKey(frame.canId, frame.isExtended); const std::shared_ptr definition = FindFrame(database, frame.canId, frame.isExtended); if (definition == nullptr) return result; result.definition = definition; result.valid = true; result.status = frame.data.size() < definition->dlc ? FrameDecodeStatus::InsufficientPayload : FrameDecodeStatus::Valid; const SelectorState selector = ReadSelector(*definition, frame); result.signals.reserve(definition->signals.size()); for (const DecodeSignal &signal: definition->signals) { DecodedSignalValue decoded = DecodeOneSignal(signal, definition->dlc, frame, selector); if (!decoded.valid && decoded.status != SignalDecodeStatus::Inactive && result.status == FrameDecodeStatus::Valid) result.status = FrameDecodeStatus::SignalErrors; decoded.definition = std::shared_ptr(definition, &signal); decoded.key = SignalKey(result.key, signal.name); result.signals.push_back(std::move(decoded)); } return result; } bool DbcDecoder::IsValidDefinition(const DecodeSignal &signal, std::uint8_t dlc) { if (signal.length == 0U || signal.length > 64U || (signal.byteOrder != ByteOrder::Intel && signal.byteOrder != ByteOrder::Motorola) || (signal.valueType != ValueType::Unsigned && signal.valueType != ValueType::Signed) || (signal.multiplexing.role != MultiplexRole::Unconditional && signal.multiplexing.role != MultiplexRole::Selector && signal.multiplexing.role != MultiplexRole::Branch)) return false; return IsValidSignalLayout(signal.startBit, signal.length, signal.byteOrder == ByteOrder::Intel, dlc); } DbcDecoder::SelectorState DbcDecoder::ReadSelector(const DecodeFrame &definition, const RawCanFrame &frame) { SelectorState selector; std::size_t count = 0U; for (const DecodeSignal &signal: definition.signals) { if (signal.multiplexing.role == MultiplexRole::Selector) { selector.definition = &signal; ++count; } } if (count != 1U) return selector; const DecodeSignal &signal = *selector.definition; selector.valid = signal.valueType == ValueType::Unsigned && IsValidDefinition(signal, definition.dlc); selector.available = selector.valid && ExtractUnsigned(frame.data, signal, selector.value); return selector; } DecodedSignalValue DbcDecoder::DecodeOneSignal(const DecodeSignal &signal, std::uint8_t dlc, const RawCanFrame &frame, const SelectorState &selector) { DecodedSignalValue decoded; std::uint64_t unsignedValue = 0U; if (!IsValidDefinition(signal, dlc) || (signal.multiplexing.role != MultiplexRole::Unconditional && !selector.valid)) { return decoded; } if (signal.multiplexing.role == MultiplexRole::Branch) { if (selector.definition->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector.definition->length)) { return decoded; } if (!selector.available) { decoded.status = SignalDecodeStatus::SelectorUnavailable; return decoded; } if (signal.multiplexing.value != selector.value) { decoded.status = SignalDecodeStatus::Inactive; return decoded; } } if (!ExtractUnsigned(frame.data, signal, unsignedValue)) { decoded.status = SignalDecodeStatus::InsufficientPayload; return decoded; } if (signal.valueType == ValueType::Signed) decoded.rawValue = SignExtend(unsignedValue, signal.length); else decoded.rawValue = unsignedValue; double numericValue; if (const std::int64_t *signedValue = std::get_if(&decoded.rawValue)) numericValue = static_cast(*signedValue); else numericValue = static_cast(std::get(decoded.rawValue)); decoded.physicalValue = numericValue * signal.factor + signal.offset; if (!std::isfinite(decoded.physicalValue)) { decoded.status = SignalDecodeStatus::PhysicalConversionFailed; return decoded; } decoded.valid = true; decoded.status = SignalDecodeStatus::Valid; return decoded; } bool DbcDecoder::ExtractUnsigned(const std::vector &data, const DecodeSignal &signal, std::uint64_t &value) { if ((signal.length == 0U) || (signal.length > 64U)) return false; if (signal.byteOrder == ByteOrder::Intel) return ExtractIntel(data, signal.startBit, signal.length, value); return ExtractMotorola(data, signal.startBit, signal.length, value); } bool DbcDecoder::ExtractIntel(const std::vector &data, std::uint32_t startBit, std::uint32_t length, std::uint64_t &value) { value = 0U; for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) { const std::uint64_t absoluteBit = std::uint64_t(startBit) + bitIndex; const std::uint64_t byteIndex = absoluteBit / 8U; const std::uint32_t bitInByte = absoluteBit % 8U; if (byteIndex >= data.size()) return false; const std::uint64_t bitValue = (static_cast((data[byteIndex] >> bitInByte) & 0x01U) << bitIndex); value |= bitValue; } return true; } bool DbcDecoder::ExtractMotorola(const std::vector &data, std::uint32_t startBit, std::uint32_t length, std::uint64_t &value) { /* * DBC Motorola bit numbering: * - startBit points to the most significant bit of the signal * - inside a byte, bit numbering goes 7..0 * - crossing byte boundary moves to the next byte, bit 7 * Example: a signal starting at 7 follows 7..0, 15..8, 23..16. */ value = 0U; std::size_t byteIndex = startBit / 8U; std::uint32_t bitInByte = startBit % 8U; for (std::uint32_t bitIndex = 0U; bitIndex < length; ++bitIndex) { if (byteIndex >= data.size()) return false; value <<= 1U; value |= static_cast((data[byteIndex] >> bitInByte) & 0x01U); if (bitInByte == 0U) { ++byteIndex; bitInByte = 7U; } else --bitInByte; } return true; } std::int64_t DbcDecoder::SignExtend(std::uint64_t value, std::uint32_t bitLength) { if ((bitLength == 0U) || (bitLength > 64U)) return 0; const std::uint64_t signMask = std::uint64_t(1U) << (bitLength - 1U); const std::uint64_t valueMask = (bitLength == 64U) ? ~std::uint64_t(0U) : (std::uint64_t(1U) << bitLength) - 1U; value &= valueMask; if ((value & signMask) == 0U) return static_cast(value); // The complemented magnitude fits int64_t, including for INT64_MIN. return -1 - static_cast((~value) & valueMask); }