/** * @file dbc_decoder.h * @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. */ #ifndef DBC_DECODER_H #define DBC_DECODER_H #include #include #include #include "decode_database.h" /** * @brief Raw CAN frame used for runtime or trace decoding. */ struct RawCanFrame { std::uint32_t canId = 0U; /**< Normalized CAN ID. */ bool isExtended = false; /**< true for extended frame. */ std::vector data; /**< Payload bytes. */ RawCanFrame() = default; }; enum class SignalDecodeStatus { InvalidDefinition, InsufficientPayload, SelectorUnavailable, Inactive, Valid, PhysicalConversionFailed }; /** Frame summary: short payload takes precedence over individual signal errors. */ enum class FrameDecodeStatus { UnknownFrame, InsufficientPayload, SignalErrors, Valid }; /** * @brief One decoded signal value. */ struct DecodedSignalValue { std::shared_ptr definition; /**< Owning immutable definition. */ SignalKey key; /**< Stable application identifier. */ RawSignalValue rawValue = std::uint64_t(0U); /**< Exact raw value for Valid or PhysicalConversionFailed. */ double physicalValue = 0.0; /**< Conversion result, possibly NaN/Inf on failure. */ bool valid = false; /**< true if decoding succeeded. */ SignalDecodeStatus status = SignalDecodeStatus::InvalidDefinition; /** Lookup using the raw integer; nullptr for invalid or unmapped values. */ const std::string *GetValueDescription() const { return valid && definition ? FindValueDescription(definition->valueDescriptions, rawValue) : nullptr; } DecodedSignalValue() = default; }; /** * @brief Fully decoded frame. */ struct DecodedFrameValue { std::shared_ptr definition; /**< Owning immutable definition. */ FrameKey key; /**< Stable application identifier. */ std::vector signals; /**< Decoded signal values. */ bool valid = false; /**< true if frame was matched. */ FrameDecodeStatus status = FrameDecodeStatus::UnknownFrame; /**< Inspect signals for individual failures. */ DecodedFrameValue() = default; }; /** * @brief Runtime CAN decoder using prebuilt decode database. */ class DbcDecoder { public: /** * @brief Find frame definition by CAN ID. * @param database Runtime decode database. * @param canId Normalized CAN ID. * @param isExtended true for extended frame. * @return Owning immutable frame handle or nullptr. Safe across reload. */ std::shared_ptr FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const; /** * @brief Decode one raw CAN frame. * @param database Runtime decode database. * @param frame Raw CAN frame. * Short payloads decode available signals; bytes beyond declared DLC are ignored. * @return Decoded frame value. */ DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const; private: static bool IsValidDefinition(const DecodeSignal &signal, std::uint8_t dlc); struct SelectorState { const DecodeSignal *definition = nullptr; bool valid = false; bool available = false; std::uint64_t value = 0U; }; static SelectorState ReadSelector(const DecodeFrame &definition, const RawCanFrame &frame); static DecodedSignalValue DecodeOneSignal(const DecodeSignal &signal, std::uint8_t dlc, const RawCanFrame &frame, const SelectorState &selector); static bool ExtractUnsigned(const std::vector &data, const DecodeSignal &signal, std::uint64_t &value); static bool ExtractIntel(const std::vector &data, std::uint32_t startBit, std::uint32_t length, std::uint64_t &value); static bool ExtractMotorola(const std::vector &data, std::uint32_t startBit, std::uint32_t length, std::uint64_t &value); static std::int64_t SignExtend(std::uint64_t value, std::uint32_t bitLength); }; #endif /* DBC_DECODER_H */