Closes #14
This commit is contained in:
1 parent
51fcdb88ac
commit
0708316a37
155 files changed
+5190
-2691
No files matched your search
@@ -1,4 +1,5 @@
|
||||
SOURCES += \
|
||||
$$PWD/decode_database.cpp \
|
||||
$$PWD/dbc_decode_builder.cpp \
|
||||
$$PWD/dbc_decoder.cpp \
|
||||
$$PWD/dbc_parser.cpp \
|
||||
@@ -7,6 +8,7 @@ SOURCES += \
|
||||
$$PWD/tree_node.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/definition_key.h \
|
||||
$$PWD/dbc_diagnostic.h \
|
||||
$$PWD/multiplexing.h \
|
||||
$$PWD/dbc_database.h \
|
||||
|
||||
@@ -10,11 +10,13 @@
|
||||
*/
|
||||
|
||||
#include "dbc_decode_builder.h"
|
||||
#include <utility>
|
||||
|
||||
DecodeDatabase DbcDecodeBuilder::Build(const DbcDatabase &source) const {
|
||||
DecodeDatabase result;
|
||||
std::vector<DecodeFrame> frames;
|
||||
frames.reserve(source.frames.size());
|
||||
|
||||
for (const FrameInfo &sourceFrame : source.frames) {
|
||||
for (const FrameInfo &sourceFrame: source.frames) {
|
||||
DecodeFrame targetFrame;
|
||||
|
||||
targetFrame.name = sourceFrame.name;
|
||||
@@ -26,7 +28,8 @@ DecodeDatabase DbcDecodeBuilder::Build(const DbcDatabase &source) const {
|
||||
targetFrame.transmitter = sourceFrame.transmitter;
|
||||
targetFrame.comment = sourceFrame.comment;
|
||||
|
||||
for (const SignalInfo &sourceSignal : sourceFrame.signals) {
|
||||
targetFrame.signals.reserve(sourceFrame.signals.size());
|
||||
for (const SignalInfo &sourceSignal: sourceFrame.signals) {
|
||||
DecodeSignal targetSignal;
|
||||
|
||||
targetSignal.multiplexing = sourceSignal.multiplexing;
|
||||
@@ -44,13 +47,11 @@ DecodeDatabase DbcDecodeBuilder::Build(const DbcDatabase &source) const {
|
||||
targetSignal.comment = sourceSignal.comment;
|
||||
targetSignal.valueDescriptions = sourceSignal.valueDescriptions;
|
||||
|
||||
targetFrame.signals.push_back(targetSignal);
|
||||
targetFrame.signals.push_back(std::move(targetSignal));
|
||||
}
|
||||
|
||||
result.frames.push_back(targetFrame);
|
||||
result.frameIndexByKey[FrameKey(targetFrame.canId, targetFrame.isExtended)] =
|
||||
result.frames.size() - 1U;
|
||||
frames.push_back(std::move(targetFrame));
|
||||
}
|
||||
|
||||
return result;
|
||||
return DecodeDatabase(std::move(frames));
|
||||
}
|
||||
@@ -23,7 +23,8 @@ public:
|
||||
/**
|
||||
* @brief Build runtime decode database.
|
||||
* @param source Parsed DBC database.
|
||||
* @return Runtime-ready decode database.
|
||||
* @return Immutable runtime snapshot independent of source lifetime.
|
||||
* @throws std::invalid_argument for duplicate frame keys or signal names.
|
||||
*/
|
||||
DecodeDatabase Build(const DbcDatabase &source) const;
|
||||
};
|
||||
|
||||
+18
-24
@@ -10,28 +10,19 @@
|
||||
*/
|
||||
|
||||
#include "dbc_decoder.h"
|
||||
#include <utility>
|
||||
|
||||
const DecodeFrame *DbcDecoder::FindFrame(const DecodeDatabase &database,
|
||||
std::uint32_t canId,
|
||||
bool isExtended) const {
|
||||
const FrameKey key(canId, isExtended);
|
||||
const std::unordered_map<FrameKey, std::size_t, FrameKeyHasher>::const_iterator it =
|
||||
database.frameIndexByKey.find(key);
|
||||
|
||||
if (it == database.frameIndexByKey.end())
|
||||
return nullptr;
|
||||
|
||||
const std::size_t index = it->second;
|
||||
if (index >= database.frames.size())
|
||||
return nullptr;
|
||||
|
||||
return &database.frames[index];
|
||||
std::shared_ptr<const DecodeFrame> 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;
|
||||
const DecodeFrame *definition = FindFrame(database, frame.canId, frame.isExtended);
|
||||
result.key = FrameKey(frame.canId, frame.isExtended);
|
||||
const std::shared_ptr<const DecodeFrame> definition = FindFrame(database, frame.canId, frame.isExtended);
|
||||
|
||||
if (definition == nullptr)
|
||||
return result;
|
||||
@@ -40,17 +31,22 @@ DecodedFrameValue DbcDecoder::Decode(const DecodeDatabase &database,
|
||||
result.valid = true;
|
||||
|
||||
const SelectorState selector = ReadSelector(*definition, frame);
|
||||
for (const DecodeSignal &signal : definition->signals)
|
||||
result.signals.push_back(DecodeOneSignal(signal, frame, selector));
|
||||
result.signals.reserve(definition->signals.size());
|
||||
for (const DecodeSignal &signal: definition->signals) {
|
||||
DecodedSignalValue decoded = DecodeOneSignal(signal, frame, selector);
|
||||
decoded.definition = std::shared_ptr<const DecodeSignal>(definition, &signal);
|
||||
decoded.key = SignalKey(result.key, signal.name);
|
||||
result.signals.push_back(std::move(decoded));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DbcDecoder::SelectorState DbcDecoder::ReadSelector(const DecodeFrame &definition,
|
||||
const RawCanFrame &frame) {
|
||||
const RawCanFrame &frame) {
|
||||
SelectorState selector;
|
||||
std::size_t count = 0U;
|
||||
for (const DecodeSignal &signal : definition.signals) {
|
||||
for (const DecodeSignal &signal: definition.signals) {
|
||||
if (signal.multiplexing.role == MultiplexRole::Selector) {
|
||||
selector.definition = &signal;
|
||||
++count;
|
||||
@@ -67,13 +63,11 @@ DbcDecoder::SelectorState DbcDecoder::ReadSelector(const DecodeFrame &definition
|
||||
}
|
||||
|
||||
DecodedSignalValue DbcDecoder::DecodeOneSignal(const DecodeSignal &signal,
|
||||
const RawCanFrame &frame,
|
||||
const SelectorState &selector) {
|
||||
const RawCanFrame &frame,
|
||||
const SelectorState &selector) {
|
||||
DecodedSignalValue decoded;
|
||||
std::uint64_t unsignedValue = 0U;
|
||||
|
||||
decoded.definition = &signal;
|
||||
|
||||
if (signal.length == 0U || signal.length > 64U ||
|
||||
(signal.multiplexing.role != MultiplexRole::Unconditional && !selector.valid)) {
|
||||
return decoded;
|
||||
|
||||
+16
-14
@@ -22,9 +22,9 @@
|
||||
* @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<std::uint8_t> data; /**< Payload bytes. */
|
||||
std::uint32_t canId = 0U; /**< Normalized CAN ID. */
|
||||
bool isExtended = false; /**< true for extended frame. */
|
||||
std::vector<std::uint8_t> data; /**< Payload bytes. */
|
||||
|
||||
RawCanFrame() = default;
|
||||
};
|
||||
@@ -41,10 +41,11 @@ enum class SignalDecodeStatus {
|
||||
* @brief One decoded signal value.
|
||||
*/
|
||||
struct DecodedSignalValue {
|
||||
const DecodeSignal *definition = nullptr; /**< Signal definition. */
|
||||
RawSignalValue rawValue = std::uint64_t(0U); /**< Exact signed or unsigned raw value. */
|
||||
double physicalValue = 0.0; /**< Converted physical value. */
|
||||
bool valid = false; /**< true if decoding succeeded. */
|
||||
std::shared_ptr<const DecodeSignal> definition; /**< Owning immutable definition. */
|
||||
SignalKey key; /**< Stable application identifier. */
|
||||
RawSignalValue rawValue = std::uint64_t(0U); /**< Exact signed or unsigned raw value. */
|
||||
double physicalValue = 0.0; /**< Converted physical value. */
|
||||
bool valid = false; /**< true if decoding succeeded. */
|
||||
SignalDecodeStatus status = SignalDecodeStatus::InvalidDefinition;
|
||||
|
||||
/** Lookup using the raw integer; nullptr for invalid or unmapped values. */
|
||||
@@ -59,9 +60,10 @@ struct DecodedSignalValue {
|
||||
* @brief Fully decoded frame.
|
||||
*/
|
||||
struct DecodedFrameValue {
|
||||
const DecodeFrame *definition = nullptr; /**< Frame definition. */
|
||||
std::vector<DecodedSignalValue> signals; /**< Decoded signal values. */
|
||||
bool valid = false; /**< true if frame was matched. */
|
||||
std::shared_ptr<const DecodeFrame> definition; /**< Owning immutable definition. */
|
||||
FrameKey key; /**< Stable application identifier. */
|
||||
std::vector<DecodedSignalValue> signals; /**< Decoded signal values. */
|
||||
bool valid = false; /**< true if frame was matched. */
|
||||
|
||||
DecodedFrameValue() = default;
|
||||
};
|
||||
@@ -76,11 +78,11 @@ public:
|
||||
* @param database Runtime decode database.
|
||||
* @param canId Normalized CAN ID.
|
||||
* @param isExtended true for extended frame.
|
||||
* @return Pointer to frame definition or nullptr.
|
||||
* @return Owning immutable frame handle or nullptr. Safe across reload.
|
||||
*/
|
||||
const DecodeFrame *FindFrame(const DecodeDatabase &database,
|
||||
std::uint32_t canId,
|
||||
bool isExtended) const;
|
||||
std::shared_ptr<const DecodeFrame> FindFrame(const DecodeDatabase &database,
|
||||
std::uint32_t canId,
|
||||
bool isExtended) const;
|
||||
|
||||
/**
|
||||
* @brief Decode one raw CAN frame.
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2026 Dim Himro
|
||||
|
||||
#include "decode_database.h"
|
||||
#include <stdexcept>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
DecodeDatabase::Storage::Storage(std::vector<DecodeFrame> definitions)
|
||||
: frames(std::move(definitions)) {
|
||||
frameIndexByKey.reserve(frames.size());
|
||||
for (std::size_t index = 0U; index < frames.size(); ++index) {
|
||||
const DecodeFrame &frame = frames[index];
|
||||
if (!frameIndexByKey.emplace(frame.GetKey(), index).second)
|
||||
throw std::invalid_argument("Duplicate runtime frame key");
|
||||
std::unordered_set<std::string> names;
|
||||
for (const DecodeSignal &signal: frame.signals) {
|
||||
if (!names.insert(signal.name).second)
|
||||
throw std::invalid_argument("Duplicate runtime signal key");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DecodeDatabase::DecodeDatabase(std::vector<DecodeFrame> frames)
|
||||
: storage(std::make_shared<const Storage>(std::move(frames))) {
|
||||
}
|
||||
|
||||
const std::vector<DecodeFrame> &DecodeDatabase::GetFrames() const {
|
||||
static const std::vector<DecodeFrame> empty;
|
||||
return storage ? storage->frames : empty;
|
||||
}
|
||||
|
||||
std::shared_ptr<const DecodeFrame> DecodeDatabase::FindFrame(const FrameKey &key) const {
|
||||
if (!storage)
|
||||
return nullptr;
|
||||
const std::unordered_map<FrameKey, std::size_t, FrameKeyHasher>::const_iterator it =
|
||||
storage->frameIndexByKey.find(key);
|
||||
if (it == storage->frameIndexByKey.end())
|
||||
return nullptr;
|
||||
return std::shared_ptr<const DecodeFrame>(storage, &storage->frames[it->second]);
|
||||
}
|
||||
|
||||
std::shared_ptr<const DecodeSignal> DecodeDatabase::FindSignal(const SignalKey &key) const {
|
||||
const std::shared_ptr<const DecodeFrame> frame = FindFrame(key.frame);
|
||||
if (!frame)
|
||||
return nullptr;
|
||||
for (const DecodeSignal &signal: frame->signals) {
|
||||
if (signal.name == key.name)
|
||||
return std::shared_ptr<const DecodeSignal>(frame, &signal);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
+53
-53
@@ -12,9 +12,11 @@
|
||||
#ifndef DECODE_DATABASE_H
|
||||
#define DECODE_DATABASE_H
|
||||
|
||||
#include "value_descriptions.h"
|
||||
#include "definition_key.h"
|
||||
#include "multiplexing.h"
|
||||
#include "value_descriptions.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -40,19 +42,19 @@ enum class ValueType {
|
||||
*/
|
||||
struct DecodeSignal {
|
||||
Multiplexing multiplexing;
|
||||
std::string name; /**< Signal name. */
|
||||
std::uint32_t startBit = 0U; /**< DBC start bit. */
|
||||
std::uint32_t length = 0U; /**< Signal length in bits. */
|
||||
ByteOrder byteOrder = ByteOrder::Intel; /**< Intel or Motorola. */
|
||||
ValueType valueType = ValueType::Unsigned; /**< Signed or unsigned. */
|
||||
double factor = 1.0; /**< Scaling factor. */
|
||||
double offset = 0.0; /**< Physical offset. */
|
||||
double minimum = 0.0; /**< Minimum physical value. */
|
||||
double maximum = 0.0; /**< Maximum physical value. */
|
||||
std::string unit; /**< Physical unit. */
|
||||
std::vector<std::string> receivers; /**< Receivers. */
|
||||
ValueDescriptions valueDescriptions; /**< Raw integer state descriptions. */
|
||||
std::string comment; /**< Comment. */
|
||||
std::string name; /**< Signal name. */
|
||||
std::uint32_t startBit = 0U; /**< DBC start bit. */
|
||||
std::uint32_t length = 0U; /**< Signal length in bits. */
|
||||
ByteOrder byteOrder = ByteOrder::Intel; /**< Intel or Motorola. */
|
||||
ValueType valueType = ValueType::Unsigned; /**< Signed or unsigned. */
|
||||
double factor = 1.0; /**< Scaling factor. */
|
||||
double offset = 0.0; /**< Physical offset. */
|
||||
double minimum = 0.0; /**< Minimum physical value. */
|
||||
double maximum = 0.0; /**< Maximum physical value. */
|
||||
std::string unit; /**< Physical unit. */
|
||||
std::vector<std::string> receivers; /**< Receivers. */
|
||||
ValueDescriptions valueDescriptions; /**< Raw integer state descriptions. */
|
||||
std::string comment; /**< Comment. */
|
||||
|
||||
DecodeSignal() = default;
|
||||
};
|
||||
@@ -61,54 +63,52 @@ struct DecodeSignal {
|
||||
* @brief Runtime-ready frame definition.
|
||||
*/
|
||||
struct DecodeFrame {
|
||||
std::string name; /**< Frame name. */
|
||||
std::uint32_t canId = 0U; /**< Normalized CAN ID. */
|
||||
bool isExtended = false; /**< true for extended frame. */
|
||||
std::uint8_t dlc = 0U; /**< Payload length. */
|
||||
std::uint32_t pgn = 0U; /**< PGN if available. */
|
||||
bool hasPgn = false; /**< true if PGN is valid. */
|
||||
std::string transmitter; /**< Transmitter ECU. */
|
||||
std::string comment; /**< Frame comment. */
|
||||
std::vector<DecodeSignal> signals; /**< Signal definitions. */
|
||||
std::string name; /**< Frame name. */
|
||||
std::uint32_t canId = 0U; /**< Normalized CAN ID. */
|
||||
bool isExtended = false; /**< true for extended frame. */
|
||||
std::uint8_t dlc = 0U; /**< Payload length. */
|
||||
std::uint32_t pgn = 0U; /**< PGN if available. */
|
||||
bool hasPgn = false; /**< true if PGN is valid. */
|
||||
std::string transmitter; /**< Transmitter ECU. */
|
||||
std::string comment; /**< Frame comment. */
|
||||
std::vector<DecodeSignal> signals; /**< Signal definitions. */
|
||||
|
||||
DecodeFrame() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Key for fast frame lookup.
|
||||
*/
|
||||
struct FrameKey {
|
||||
std::uint32_t canId = 0U;
|
||||
bool isExtended = false;
|
||||
|
||||
FrameKey() = default;
|
||||
|
||||
FrameKey(std::uint32_t id, bool extended)
|
||||
: canId(id), isExtended(extended) {
|
||||
}
|
||||
|
||||
bool operator==(const FrameKey &other) const {
|
||||
return (canId == other.canId) && (isExtended == other.isExtended);
|
||||
FrameKey GetKey() const {
|
||||
return FrameKey(canId, isExtended);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Hasher for frame key.
|
||||
* @brief Immutable runtime snapshot. Copies share storage; reload replaces a snapshot.
|
||||
* Owning lookup handles and decoded results keep old definitions alive.
|
||||
*/
|
||||
struct FrameKeyHasher {
|
||||
std::size_t operator()(const FrameKey &key) const {
|
||||
const std::size_t a = static_cast<std::size_t>(key.canId);
|
||||
const std::size_t b = key.isExtended ? 1U : 0U;
|
||||
return (a * 1315423911U) ^ b;
|
||||
}
|
||||
};
|
||||
class DecodeDatabase {
|
||||
public:
|
||||
DecodeDatabase() = default;
|
||||
/**
|
||||
* Freeze definitions and build the frame index.
|
||||
* Do not retain mutable aliases into moved input vectors.
|
||||
* @throws std::invalid_argument for duplicate frame keys or signal names.
|
||||
*/
|
||||
explicit DecodeDatabase(std::vector<DecodeFrame> frames);
|
||||
|
||||
/**
|
||||
* @brief Runtime decode database with fast lookup by CAN ID.
|
||||
*/
|
||||
struct DecodeDatabase {
|
||||
std::vector<DecodeFrame> frames;
|
||||
std::unordered_map<FrameKey, std::size_t, FrameKeyHasher> frameIndexByKey;
|
||||
/** Borrowed view, valid while this snapshot remains alive and unchanged. */
|
||||
const std::vector<DecodeFrame> &GetFrames() const;
|
||||
/** Owning handles retain the entire snapshot across reload or destruction. */
|
||||
std::shared_ptr<const DecodeFrame> FindFrame(const FrameKey &key) const;
|
||||
std::shared_ptr<const DecodeSignal> FindSignal(const SignalKey &key) const;
|
||||
|
||||
private:
|
||||
struct Storage {
|
||||
std::vector<DecodeFrame> frames;
|
||||
std::unordered_map<FrameKey, std::size_t, FrameKeyHasher> frameIndexByKey;
|
||||
|
||||
explicit Storage(std::vector<DecodeFrame> definitions);
|
||||
};
|
||||
|
||||
std::shared_ptr<const Storage> storage;
|
||||
};
|
||||
|
||||
#endif /* DECODE_DATABASE_H */
|
||||
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2026 Dim Himro
|
||||
|
||||
#ifndef DEFINITION_KEY_H
|
||||
#define DEFINITION_KEY_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* @brief Stable frame identifier: normalized CAN ID and frame type.
|
||||
*/
|
||||
struct FrameKey {
|
||||
std::uint32_t canId = 0U;
|
||||
bool isExtended = false;
|
||||
|
||||
FrameKey() = default;
|
||||
|
||||
FrameKey(std::uint32_t id, bool extended)
|
||||
: canId(id), isExtended(extended) {
|
||||
}
|
||||
|
||||
bool operator==(const FrameKey &other) const {
|
||||
return (canId == other.canId) && (isExtended == other.isExtended);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Hasher for frame key.
|
||||
*/
|
||||
struct FrameKeyHasher {
|
||||
std::size_t operator()(const FrameKey &key) const {
|
||||
const std::size_t a = static_cast<std::size_t>(key.canId);
|
||||
const std::size_t b = key.isExtended ? 1U : 0U;
|
||||
return (a * 1315423911U) ^ b;
|
||||
}
|
||||
};
|
||||
|
||||
/** Stable signal identifier within one logical DBC database. */
|
||||
struct SignalKey {
|
||||
FrameKey frame;
|
||||
std::string name;
|
||||
|
||||
SignalKey() = default;
|
||||
SignalKey(FrameKey frameKey, std::string signalName)
|
||||
: frame(frameKey), name(std::move(signalName)) {
|
||||
}
|
||||
|
||||
bool operator==(const SignalKey &other) const {
|
||||
return frame == other.frame && name == other.name;
|
||||
}
|
||||
};
|
||||
|
||||
struct SignalKeyHasher {
|
||||
std::size_t operator()(const SignalKey &key) const {
|
||||
return FrameKeyHasher()(key.frame) ^ (std::hash<std::string>()(key.name) << 1U);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DEFINITION_KEY_H */
|
||||
Reference in new issue
Block a user