simlyfy
This commit is contained in:
1 parent
849ce31e2f
commit
a55d1c58ed
272 files changed
+41866
-261
No files matched your search
+31
-16
@@ -9,6 +9,9 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief Target scope of an attribute definition or assignment.
|
||||
*/
|
||||
enum class AttributeScope {
|
||||
Database,
|
||||
Node,
|
||||
@@ -17,6 +20,9 @@ enum class AttributeScope {
|
||||
Environment
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DBC attribute storage type. HEX values use decimal integer syntax.
|
||||
*/
|
||||
enum class AttributeType {
|
||||
Integer,
|
||||
Hex,
|
||||
@@ -25,29 +31,38 @@ enum class AttributeType {
|
||||
Enum
|
||||
};
|
||||
|
||||
/** @brief Typed attribute value; ENUM uses a zero-based integer index. */
|
||||
using AttributeValue = std::variant<std::int64_t, double, std::string>;
|
||||
/** @brief Effective attribute values indexed by definition name. */
|
||||
using AttributeMap = std::map<std::string, AttributeValue>;
|
||||
|
||||
/**
|
||||
* @brief Attribute type, permitted range, and optional default.
|
||||
*/
|
||||
struct AttributeDefinition {
|
||||
AttributeScope scope = AttributeScope::Database;
|
||||
AttributeType type = AttributeType::String;
|
||||
std::int64_t integerMinimum = 0;
|
||||
std::int64_t integerMaximum = 0;
|
||||
double minimum = 0.0;
|
||||
double maximum = 0.0;
|
||||
std::vector<std::string> enumValues;
|
||||
std::optional<AttributeValue> defaultValue;
|
||||
AttributeScope scope = AttributeScope::Database; /**< Target scope; database when no scope marker is present. */
|
||||
AttributeType type = AttributeType::String; /**< Type used to validate values. */
|
||||
std::int64_t integerMinimum = 0; /**< Inclusive INT, HEX, or ENUM lower bound. */
|
||||
std::int64_t integerMaximum = 0; /**< Inclusive INT, HEX, or ENUM upper bound. */
|
||||
double minimum = 0.0; /**< Inclusive FLOAT lower bound. */
|
||||
double maximum = 0.0; /**< Inclusive FLOAT upper bound. */
|
||||
std::vector<std::string> enumValues; /**< ENUM labels in index order. */
|
||||
std::optional<AttributeValue> defaultValue; /**< Validated default; empty when not declared. */
|
||||
};
|
||||
|
||||
/** Explicit assignment; defaults remain on definitions. Named nodes/environment
|
||||
* variables are retained without validating declarations, which are not parsed. */
|
||||
/**
|
||||
* @brief Explicit assignment; defaults remain on definitions.
|
||||
*
|
||||
* Named nodes/environment variables are retained without validating declarations,
|
||||
* which are not parsed.
|
||||
*/
|
||||
struct AttributeAssignment {
|
||||
std::string name;
|
||||
AttributeScope scope = AttributeScope::Database;
|
||||
std::uint32_t canId = 0U;
|
||||
bool isExtended = false;
|
||||
std::string targetName;
|
||||
AttributeValue value;
|
||||
std::string name; /**< Attribute definition name. */
|
||||
AttributeScope scope = AttributeScope::Database; /**< Target scope; database when no scope marker is present. */
|
||||
std::uint32_t canId = 0U; /**< Normalized frame ID for frame/signal assignments. */
|
||||
bool isExtended = false; /**< Frame type for frame/signal assignments. */
|
||||
std::string targetName; /**< Signal, node, or environment variable name. */
|
||||
AttributeValue value; /**< Validated explicit value. */
|
||||
};
|
||||
|
||||
#endif
|
||||
+20
-29
@@ -104,7 +104,8 @@ namespace {
|
||||
throw std::runtime_error("Unsupported attribute scope: " + text);
|
||||
}
|
||||
|
||||
std::int64_t Integer(const std::string &text) {
|
||||
template<class Numeric>
|
||||
Numeric ParseNumber(const std::string &text) {
|
||||
const char *begin = text.data();
|
||||
const char *end = begin + text.size();
|
||||
if (begin != end && *begin == '+') {
|
||||
@@ -112,22 +113,7 @@ namespace {
|
||||
if (begin != end && (*begin == '-' || *begin == '+'))
|
||||
throw std::runtime_error("Invalid attribute number: " + text);
|
||||
}
|
||||
std::int64_t value = 0;
|
||||
const std::from_chars_result parsed = std::from_chars(begin, end, value);
|
||||
if (begin == end || parsed.ec != std::errc() || parsed.ptr != end)
|
||||
throw std::runtime_error("Invalid attribute integer: " + text);
|
||||
return value;
|
||||
}
|
||||
|
||||
double Number(const std::string &text) {
|
||||
const char *begin = text.data();
|
||||
const char *end = begin + text.size();
|
||||
if (begin != end && *begin == '+') {
|
||||
++begin;
|
||||
if (begin != end && (*begin == '-' || *begin == '+'))
|
||||
throw std::runtime_error("Invalid attribute number: " + text);
|
||||
}
|
||||
double value = 0.0;
|
||||
Numeric value = 0;
|
||||
const std::from_chars_result parsed = std::from_chars(begin, end, value);
|
||||
if (begin == end || parsed.ec != std::errc() || parsed.ptr != end || !std::isfinite(value))
|
||||
throw std::runtime_error("Invalid attribute number: " + text);
|
||||
@@ -148,12 +134,12 @@ namespace {
|
||||
}
|
||||
if (token.quoted) throw std::runtime_error("Numeric attribute requires an unquoted number.");
|
||||
if (definition.type == AttributeType::Float) {
|
||||
const double value = Number(token.text);
|
||||
const double value = ParseNumber<double>(token.text);
|
||||
if (value < definition.minimum || value > definition.maximum)
|
||||
throw std::runtime_error("Attribute FLOAT value outside definition range.");
|
||||
return value;
|
||||
}
|
||||
const std::int64_t value = Integer(token.text);
|
||||
const std::int64_t value = ParseNumber<std::int64_t>(token.text);
|
||||
if (value < definition.integerMinimum || value > definition.integerMaximum)
|
||||
throw std::runtime_error("Attribute integer/ENUM value outside definition range.");
|
||||
return value;
|
||||
@@ -171,14 +157,14 @@ namespace {
|
||||
const std::string type = tokens.Word();
|
||||
if (type == "INT" || type == "HEX") {
|
||||
definition.type = type == "INT" ? AttributeType::Integer : AttributeType::Hex;
|
||||
definition.integerMinimum = Integer(tokens.Word());
|
||||
definition.integerMaximum = Integer(tokens.Word());
|
||||
definition.integerMinimum = ParseNumber<std::int64_t>(tokens.Word());
|
||||
definition.integerMaximum = ParseNumber<std::int64_t>(tokens.Word());
|
||||
if (definition.integerMinimum > definition.integerMaximum)
|
||||
throw std::runtime_error("Reversed attribute integer range.");
|
||||
} else if (type == "FLOAT") {
|
||||
definition.type = AttributeType::Float;
|
||||
definition.minimum = Number(tokens.Word());
|
||||
definition.maximum = Number(tokens.Word());
|
||||
definition.minimum = ParseNumber<double>(tokens.Word());
|
||||
definition.maximum = ParseNumber<double>(tokens.Word());
|
||||
if (definition.minimum > definition.maximum)
|
||||
throw std::runtime_error("Reversed attribute FLOAT range.");
|
||||
} else if (type == "STRING") {
|
||||
@@ -217,7 +203,7 @@ namespace {
|
||||
}
|
||||
|
||||
void ParseId(const std::string &text, AttributeAssignment &assignment) {
|
||||
const std::int64_t raw = Integer(text);
|
||||
const std::int64_t raw = ParseNumber<std::int64_t>(text);
|
||||
if (raw < 0 || raw > std::numeric_limits<std::uint32_t>::max() || (raw & 0x60000000U) != 0)
|
||||
throw std::runtime_error("Invalid attribute CAN ID.");
|
||||
const std::uint32_t id = static_cast<std::uint32_t>(raw);
|
||||
@@ -247,7 +233,12 @@ namespace {
|
||||
|
||||
void ApplyDefault(DbcDatabase &database, const std::string &name, const AttributeDefinition &definition) {
|
||||
if (!definition.defaultValue) return;
|
||||
if (definition.scope == AttributeScope::Database) database.attributes[name] = *definition.defaultValue;
|
||||
if (definition.scope == AttributeScope::Database) {
|
||||
database.attributes[name] = *definition.defaultValue;
|
||||
return;
|
||||
}
|
||||
if (definition.scope != AttributeScope::Frame && definition.scope != AttributeScope::Signal)
|
||||
return;
|
||||
for (FrameInfo &frame: database.frames) {
|
||||
if (definition.scope == AttributeScope::Frame) frame.attributes[name] = *definition.defaultValue;
|
||||
if (definition.scope == AttributeScope::Signal) {
|
||||
@@ -266,20 +257,20 @@ void DbcParseContext::ResolveAttributes(const std::string &filePath, std::vector
|
||||
std::vector<std::size_t> assignmentLines;
|
||||
// Resolve each phase independently of source ordering.
|
||||
const char *keywords[] = {"BA_DEF_", "BA_DEF_DEF_", "BA_"};
|
||||
for (int phase = 0; phase < 3; ++phase) {
|
||||
for (const char *phase: keywords) {
|
||||
for (const PendingAttribute &pending: pendingAttributes) {
|
||||
const std::string keyword = pending.statement.substr(0U, pending.statement.find_first_of(" \t"));
|
||||
if (keyword != keywords[phase]) continue;
|
||||
if (keyword != phase) continue;
|
||||
try {
|
||||
AttributeTokens tokens(pending.statement);
|
||||
tokens.Word();
|
||||
if (phase == 0) {
|
||||
if (keyword == "BA_DEF_") {
|
||||
Define(tokens, database);
|
||||
continue;
|
||||
}
|
||||
const std::string name = tokens.Quoted();
|
||||
AttributeDefinition &definition = FindDefinition(database, name);
|
||||
if (phase == 1) {
|
||||
if (keyword == "BA_DEF_DEF_") {
|
||||
if (definition.defaultValue) throw std::runtime_error("Duplicate attribute default: " + name);
|
||||
definition.defaultValue = Value(tokens.Take(), definition, true);
|
||||
ValidateCycleTime(name, *definition.defaultValue);
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file dbc_database.h
|
||||
* @brief
|
||||
* @brief Parsed DBC database and attribute metadata.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
@@ -21,8 +21,8 @@
|
||||
*/
|
||||
struct DbcDatabase {
|
||||
std::vector<FrameInfo> frames; /**< All frames found in the DBC file. */
|
||||
std::map<std::string, AttributeDefinition> attributeDefinitions = {};
|
||||
std::vector<AttributeAssignment> attributeAssignments = {};
|
||||
std::map<std::string, AttributeDefinition> attributeDefinitions = {}; /**< Attribute definitions indexed by name. */
|
||||
std::vector<AttributeAssignment> attributeAssignments = {}; /**< Explicit assignments in source order. */
|
||||
AttributeMap attributes = {}; /**< Effective database attributes. */
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file dbc_decode_builder.cpp
|
||||
* @brief
|
||||
* @brief Conversion of parsed metadata to runtime definitions.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file dbc_decode_builder.h
|
||||
* @brief
|
||||
* @brief Runtime decode database builder.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file dbc_decoder.cpp
|
||||
* @brief
|
||||
* @brief CAN signal extraction and physical value conversion.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
@@ -99,8 +99,7 @@ DecodedFrameValue DbcDecoder::DecodeImpl(const DecodeDatabase &database,
|
||||
}
|
||||
|
||||
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) ||
|
||||
if ((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 &&
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file dbc_decoder.h
|
||||
* @brief
|
||||
* @brief CAN frame decoding API and result types.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
@@ -29,6 +29,7 @@ struct RawCanFrame {
|
||||
RawCanFrame() = default;
|
||||
};
|
||||
|
||||
/** @brief Outcome of signal extraction and physical conversion. */
|
||||
enum class SignalDecodeStatus {
|
||||
InvalidDefinition,
|
||||
InsufficientPayload,
|
||||
@@ -56,7 +57,7 @@ struct DecodedSignalValue {
|
||||
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;
|
||||
SignalDecodeStatus status = SignalDecodeStatus::InvalidDefinition; /**< Detailed signal outcome. */
|
||||
|
||||
/** Lookup using the raw integer; nullptr for invalid or unmapped values. */
|
||||
const std::string *GetValueDescription() const {
|
||||
|
||||
+11
-7
@@ -7,6 +7,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** @brief Warning or fatal parse error. */
|
||||
enum class DbcDiagnosticSeverity {
|
||||
Warning,
|
||||
Error
|
||||
@@ -24,18 +25,21 @@ enum class DbcDiagnosticCode {
|
||||
UnsupportedAttribute
|
||||
};
|
||||
|
||||
/** @brief Diagnostic message and physical source location. */
|
||||
struct DbcDiagnostic {
|
||||
DbcDiagnosticSeverity severity;
|
||||
DbcDiagnosticCode code;
|
||||
std::string filePath;
|
||||
std::size_t lineNumber;// One-based physical line; zero for file-level errors.
|
||||
std::string message;
|
||||
DbcDiagnosticSeverity severity; /**< Message severity. */
|
||||
DbcDiagnosticCode code; /**< Stable diagnostic category. */
|
||||
std::string filePath; /**< Input file path. */
|
||||
std::size_t lineNumber; /**< One-based physical line; zero for file-level errors. */
|
||||
std::string message; /**< Human-readable diagnostic details. */
|
||||
};
|
||||
|
||||
/** @brief Parsed database and diagnostics; the database is empty on error. */
|
||||
struct DbcParseResult {
|
||||
DbcDatabase database;
|
||||
std::vector<DbcDiagnostic> diagnostics;
|
||||
DbcDatabase database; /**< Parsed content, published only on success. */
|
||||
std::vector<DbcDiagnostic> diagnostics; /**< Warnings and the first error, if any. */
|
||||
|
||||
/** @brief Return whether any diagnostic has error severity. */
|
||||
bool HasErrors() const {
|
||||
for (const DbcDiagnostic &diagnostic: diagnostics) {
|
||||
if (diagnostic.severity == DbcDiagnosticSeverity::Error)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file dbc_parser.cpp
|
||||
* @brief
|
||||
* @brief DBC file reading and diagnostic collection.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file dbc_parser.h
|
||||
* @brief
|
||||
* @brief DBC file parser and interpretation options.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
/** Explicit interpretation applied to extended frames in this file. */
|
||||
struct DbcParserOptions {
|
||||
bool enableJ1939 = false;
|
||||
bool enableJ1939 = false; /**< Derive J1939 PGNs from extended CAN IDs. */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -40,6 +40,7 @@ struct DbcParserOptions {
|
||||
*/
|
||||
class DbcParser {
|
||||
public:
|
||||
/** @brief Create a parser with explicit extended-frame interpretation options. */
|
||||
explicit DbcParser(DbcParserOptions options = {}) : options(options) {}
|
||||
|
||||
/**
|
||||
|
||||
@@ -160,13 +160,8 @@ namespace {
|
||||
* Example:
|
||||
* raw id = 0x80000000 | actual_29_bit_id
|
||||
*/
|
||||
if ((rawCanId & 0x80000000U) != 0U) {
|
||||
isExtended = true;
|
||||
normalizedCanId = (rawCanId & 0x1FFFFFFFU);
|
||||
} else {
|
||||
isExtended = (rawCanId > 0x7FFU);
|
||||
normalizedCanId = rawCanId;
|
||||
}
|
||||
isExtended = (rawCanId & 0x80000000U) != 0U || rawCanId > 0x7FFU;
|
||||
normalizedCanId = rawCanId & 0x1FFFFFFFU;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -9,65 +9,76 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
/** @brief Deferred raw value descriptions and their target. */
|
||||
struct PendingValueDescriptions {
|
||||
std::uint32_t canId;
|
||||
bool isExtended;
|
||||
std::string signalName;
|
||||
ValueDescriptions descriptions;
|
||||
std::size_t lineNumber;
|
||||
std::uint32_t canId; /**< Normalized target frame identifier. */
|
||||
bool isExtended; /**< Target frame type. */
|
||||
std::string signalName; /**< Target signal name. */
|
||||
ValueDescriptions descriptions; /**< Raw integer descriptions to merge. */
|
||||
std::size_t lineNumber; /**< One-based physical statement line. */
|
||||
};
|
||||
|
||||
/** @brief Deferred frame or signal comment and its source location. */
|
||||
struct PendingComment {
|
||||
std::uint32_t canId;
|
||||
bool isExtended;
|
||||
bool isSignal;
|
||||
std::string signalName;
|
||||
std::string comment;
|
||||
std::size_t lineNumber;
|
||||
std::uint32_t canId; /**< Normalized target frame identifier. */
|
||||
bool isExtended; /**< Target frame type. */
|
||||
bool isSignal; /**< Whether the target is a signal rather than a frame. */
|
||||
std::string signalName; /**< Target signal name. */
|
||||
std::string comment; /**< Unescaped comment text. */
|
||||
std::size_t lineNumber; /**< One-based physical statement line. */
|
||||
};
|
||||
|
||||
/** Carries deferred validation locations without parsing exception text. */
|
||||
class DbcDiagnosticError : public std::runtime_error {
|
||||
public:
|
||||
/** @brief Create an exception with a structured source diagnostic. */
|
||||
DbcDiagnosticError(DbcDiagnosticCode code, const std::string &filePath,
|
||||
std::size_t lineNumber, const std::string &message)
|
||||
: std::runtime_error(filePath + ":" + std::to_string(lineNumber) + ": " + message),
|
||||
diagnostic{DbcDiagnosticSeverity::Error, code, filePath, lineNumber, message} {}
|
||||
|
||||
DbcDiagnostic diagnostic;
|
||||
DbcDiagnostic diagnostic; /**< Structured error accompanying the exception message. */
|
||||
};
|
||||
|
||||
/** @brief Attribute statement retained for ordered resolution. */
|
||||
struct PendingAttribute {
|
||||
std::string statement;
|
||||
std::size_t lineNumber;
|
||||
std::string statement; /**< Complete attribute statement. */
|
||||
std::size_t lineNumber; /**< One-based physical statement line. */
|
||||
};
|
||||
|
||||
/** Mutable state belonging to one file parse. Handlers do not retain it. */
|
||||
struct DbcParseContext {
|
||||
DbcDatabase &database;
|
||||
FrameInfo *currentFrame = nullptr;
|
||||
bool enableJ1939 = false;
|
||||
std::size_t lineNumber = 0U;
|
||||
std::vector<PendingValueDescriptions> pendingValues = {};
|
||||
DbcDatabase &database; /**< Parsed metadata under construction. */
|
||||
FrameInfo *currentFrame = nullptr; /**< Current frame for following signal definitions. */
|
||||
bool enableJ1939 = false; /**< Explicit interpretation option for extended frames. */
|
||||
std::size_t lineNumber = 0U; /**< Physical line of the current statement. */
|
||||
std::vector<PendingValueDescriptions> pendingValues = {}; /**< Unresolved raw value descriptions. */
|
||||
|
||||
std::vector<std::vector<std::size_t>> signalLines = {};
|
||||
std::vector<std::vector<std::size_t>> signalLines = {}; /**< Signal definition lines grouped by frame. */
|
||||
/** @brief Validate selectors, branch ranges, and signal overlap. */
|
||||
void ValidateMultiplexing(const std::string &filePath) const;
|
||||
|
||||
std::vector<PendingComment> pendingComments = {};
|
||||
std::vector<PendingComment> pendingComments = {}; /**< Unresolved comments in source order. */
|
||||
/** @brief Resolve deferred comments after all definitions are known. */
|
||||
void ResolveComments(const std::string &filePath);
|
||||
|
||||
std::vector<PendingAttribute> pendingAttributes = {};
|
||||
std::vector<PendingAttribute> pendingAttributes = {}; /**< Unresolved attributes in source order. */
|
||||
/** @brief Resolve definitions, defaults, then assignments; append format warnings. */
|
||||
void ResolveAttributes(const std::string &filePath, std::vector<DbcDiagnostic> &diagnostics);
|
||||
|
||||
/** @brief Resolve deferred raw descriptions against unique targets. */
|
||||
void ResolveValueDescriptions(const std::string &filePath);
|
||||
};
|
||||
|
||||
/** @brief Interface for processing a registered DBC statement. */
|
||||
class DbcStatementHandler {
|
||||
public:
|
||||
virtual ~DbcStatementHandler() = default;
|
||||
/** @brief Process a trimmed statement using state belonging to this parse. */
|
||||
virtual void Handle(const std::string &line, DbcParseContext &context) const = 0;
|
||||
};
|
||||
|
||||
/** @brief Parse and append frame definitions. */
|
||||
class DbcFrameHandler : public DbcStatementHandler {
|
||||
public:
|
||||
void Handle(const std::string &line, DbcParseContext &context) const override;
|
||||
@@ -76,6 +87,7 @@ private:
|
||||
static FrameInfo ParseFrameLine(const std::string &line);
|
||||
};
|
||||
|
||||
/** @brief Parse and append signals to the current frame. */
|
||||
class DbcSignalHandler : public DbcStatementHandler {
|
||||
public:
|
||||
void Handle(const std::string &line, DbcParseContext &context) const override;
|
||||
@@ -84,21 +96,25 @@ private:
|
||||
static SignalInfo ParseSignalLine(const std::string &line);
|
||||
};
|
||||
|
||||
/** @brief Defer frame and signal comments for target resolution. */
|
||||
class DbcCommentHandler : public DbcStatementHandler {
|
||||
public:
|
||||
void Handle(const std::string &line, DbcParseContext &context) const override;
|
||||
};
|
||||
|
||||
/** @brief Defer typed attribute statements for resolution. */
|
||||
class DbcAttributeHandler : public DbcStatementHandler {
|
||||
public:
|
||||
void Handle(const std::string &line, DbcParseContext &context) const override;
|
||||
};
|
||||
|
||||
/** @brief Defer raw value descriptions for target resolution. */
|
||||
class DbcValueDescriptionHandler : public DbcStatementHandler {
|
||||
public:
|
||||
void Handle(const std::string &line, DbcParseContext &context) const override;
|
||||
};
|
||||
|
||||
/** @brief Reject unsupported extended multiplexing statements. */
|
||||
class DbcUnsupportedMultiplexingHandler : public DbcStatementHandler {
|
||||
public:
|
||||
void Handle(const std::string &line, DbcParseContext &context) const override;
|
||||
@@ -113,8 +129,10 @@ public:
|
||||
/** Exact-key dispatch to handlers created once per registration via TypeFactory. */
|
||||
class DbcStatementDispatcher {
|
||||
public:
|
||||
/** @brief Register supported statement handlers through TypeFactory. */
|
||||
DbcStatementDispatcher();
|
||||
|
||||
/** @brief Register or replace a handler and create its reusable instance. */
|
||||
template<class Handler>
|
||||
void RegisterType(const std::string &keyword) {
|
||||
m_factory.registerType<Handler>(keyword);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file dbc_tree_builder.cpp
|
||||
* @brief
|
||||
* @brief Construction of frame and signal metadata trees.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file dbc_tree_builder.h
|
||||
* @brief
|
||||
* @brief Metadata tree builder.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
|
||||
+10
-8
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file decode_database.h
|
||||
* @brief
|
||||
* @brief Runtime definitions and immutable indexed database.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
@@ -42,7 +42,7 @@ enum class ValueType {
|
||||
* @brief Runtime-ready signal definition.
|
||||
*/
|
||||
struct DecodeSignal {
|
||||
Multiplexing multiplexing;
|
||||
Multiplexing multiplexing; /**< Selector role and branch value. */
|
||||
std::string name; /**< Signal name. */
|
||||
std::uint32_t startBit = 0U; /**< DBC start bit. */
|
||||
std::uint32_t length = 0U; /**< Signal length in bits. */
|
||||
@@ -57,7 +57,7 @@ struct DecodeSignal {
|
||||
ValueDescriptions valueDescriptions; /**< Raw integer state descriptions. */
|
||||
std::string comment; /**< Comment. */
|
||||
|
||||
AttributeMap attributes;
|
||||
AttributeMap attributes; /**< Effective attributes after defaults and overrides. */
|
||||
|
||||
DecodeSignal() = default;
|
||||
};
|
||||
@@ -76,12 +76,13 @@ struct DecodeFrame {
|
||||
std::string comment; /**< Frame comment. */
|
||||
std::vector<DecodeSignal> signals; /**< Signal definitions. */
|
||||
|
||||
AttributeMap attributes;
|
||||
std::optional<std::string> frameFormat;
|
||||
std::optional<std::uint32_t> cycleTimeMs;
|
||||
AttributeMap attributes; /**< Effective attributes after defaults and overrides. */
|
||||
std::optional<std::string> frameFormat; /**< VFrameFormat label, when declared. */
|
||||
std::optional<std::uint32_t> cycleTimeMs; /**< GenMsgCycleTime in milliseconds, when declared. */
|
||||
|
||||
DecodeFrame() = default;
|
||||
|
||||
/** @brief Return the stable normalized frame identifier. */
|
||||
FrameKey GetKey() const {
|
||||
return FrameKey(canId, isExtended);
|
||||
}
|
||||
@@ -89,8 +90,8 @@ struct DecodeFrame {
|
||||
|
||||
/** A PGN lookup rejects multiple definitions rather than choosing by order. */
|
||||
struct PgnLookupResult {
|
||||
std::shared_ptr<const DecodeFrame> definition;
|
||||
bool ambiguous = false;
|
||||
std::shared_ptr<const DecodeFrame> definition; /**< Owning matched definition; empty if missing or ambiguous. */
|
||||
bool ambiguous = false; /**< True when multiple definitions share the requested PGN. */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -113,6 +114,7 @@ public:
|
||||
std::shared_ptr<const DecodeFrame> FindFrame(const FrameKey &key) const;
|
||||
/** Only explicitly marked hasPgn frames participate; ambiguous results have no definition. */
|
||||
PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const;
|
||||
/** @brief Return an owning signal handle, or an empty handle for a missing key. */
|
||||
std::shared_ptr<const DecodeSignal> FindSignal(const SignalKey &key) const;
|
||||
|
||||
private:
|
||||
|
||||
+11
-4
@@ -13,15 +13,17 @@
|
||||
* @brief Stable frame identifier: normalized CAN ID and frame type.
|
||||
*/
|
||||
struct FrameKey {
|
||||
std::uint32_t canId = 0U;
|
||||
bool isExtended = false;
|
||||
std::uint32_t canId = 0U; /**< Normalized CAN identifier. */
|
||||
bool isExtended = false; /**< True for extended CAN frames. */
|
||||
|
||||
FrameKey() = default;
|
||||
|
||||
/** @brief Create a key from a normalized identifier and frame type. */
|
||||
FrameKey(std::uint32_t id, bool extended)
|
||||
: canId(id), isExtended(extended) {
|
||||
}
|
||||
|
||||
/** @brief Compare all logical identity fields. */
|
||||
bool operator==(const FrameKey &other) const {
|
||||
return (canId == other.canId) && (isExtended == other.isExtended);
|
||||
}
|
||||
@@ -31,6 +33,7 @@ struct FrameKey {
|
||||
* @brief Hasher for frame key.
|
||||
*/
|
||||
struct FrameKeyHasher {
|
||||
/** @brief Hash the logical identity fields. */
|
||||
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;
|
||||
@@ -40,20 +43,24 @@ struct FrameKeyHasher {
|
||||
|
||||
/** Stable signal identifier within one logical DBC database. */
|
||||
struct SignalKey {
|
||||
FrameKey frame;
|
||||
std::string name;
|
||||
FrameKey frame; /**< Owning frame identity. */
|
||||
std::string name; /**< Signal name within the frame. */
|
||||
|
||||
SignalKey() = default;
|
||||
/** @brief Create a signal key from its frame identity and name. */
|
||||
SignalKey(FrameKey frameKey, std::string signalName)
|
||||
: frame(frameKey), name(std::move(signalName)) {
|
||||
}
|
||||
|
||||
/** @brief Compare all logical identity fields. */
|
||||
bool operator==(const SignalKey &other) const {
|
||||
return frame == other.frame && name == other.name;
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Hasher for stable signal keys. */
|
||||
struct SignalKeyHasher {
|
||||
/** @brief Hash the logical identity fields. */
|
||||
std::size_t operator()(const SignalKey &key) const {
|
||||
return FrameKeyHasher()(key.frame) ^ (std::hash<std::string>()(key.name) << 1U);
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file frame_info.h
|
||||
* @brief
|
||||
* @brief Parsed CAN frame metadata.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
@@ -33,10 +33,10 @@ struct FrameInfo {
|
||||
std::string comment; /**< Optional frame comment. */
|
||||
std::vector<SignalInfo> signals; /**< Signals contained in the frame. */
|
||||
|
||||
std::optional<std::string> frameFormat; /**< VFrameFormat enum label. */
|
||||
std::optional<std::uint32_t> cycleTimeMs; /**< GenMsgCycleTime; zero means unspecified. */
|
||||
std::optional<std::string> frameFormat; /**< VFrameFormat label, when declared. */ /**< VFrameFormat enum label. */
|
||||
std::optional<std::uint32_t> cycleTimeMs; /**< GenMsgCycleTime in milliseconds, when declared. */ /**< GenMsgCycleTime; zero means unspecified. */
|
||||
|
||||
AttributeMap attributes; /**< Effective values, including defaults. */
|
||||
AttributeMap attributes; /**< Effective attributes after defaults and overrides. */ /**< Effective values, including defaults. */
|
||||
|
||||
FrameInfo() = default;
|
||||
};
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/** @brief Unconditional signal, selector, or single-value branch. */
|
||||
enum class MultiplexRole {
|
||||
Unconditional,
|
||||
Selector,
|
||||
@@ -12,8 +13,8 @@ enum class MultiplexRole {
|
||||
|
||||
/** Basic multiplexing: one unsigned selector per frame, one raw value per branch. */
|
||||
struct Multiplexing {
|
||||
MultiplexRole role = MultiplexRole::Unconditional;
|
||||
std::uint64_t value = 0U;
|
||||
MultiplexRole role = MultiplexRole::Unconditional; /**< Signal participation in multiplexing. */
|
||||
std::uint64_t value = 0U; /**< Required raw selector value; used only by branches. */
|
||||
};
|
||||
|
||||
#endif
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file signal_info.h
|
||||
* @brief
|
||||
* @brief Parsed CAN signal metadata.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
@@ -23,7 +23,7 @@
|
||||
* @brief Describes one signal inside a DBC frame.
|
||||
*/
|
||||
struct SignalInfo {
|
||||
Multiplexing multiplexing;
|
||||
Multiplexing multiplexing; /**< Selector role and branch value. */
|
||||
std::string name; /**< Signal name. */
|
||||
std::uint32_t startBit = 0U; /**< Start bit in DBC notation. */
|
||||
std::uint32_t length = 0U; /**< Signal length in bits. */
|
||||
@@ -38,7 +38,7 @@ struct SignalInfo {
|
||||
ValueDescriptions valueDescriptions; /**< Raw integer state descriptions. */
|
||||
std::string comment; /**< Optional signal comment. */
|
||||
|
||||
AttributeMap attributes; /**< Effective values, including defaults. */
|
||||
AttributeMap attributes; /**< Effective attributes after defaults and overrides. */ /**< Effective values, including defaults. */
|
||||
|
||||
SignalInfo() = default;
|
||||
};
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file tree_node.cpp
|
||||
* @brief
|
||||
* @brief Tree node ownership and navigation.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file tree_node.h
|
||||
* @brief
|
||||
* @brief Qt-independent metadata tree nodes.
|
||||
*
|
||||
* Created: 2026-03-13
|
||||
* Author: Deeaitch (Dim. Himro)
|
||||
|
||||
+22
-20
@@ -19,9 +19,9 @@
|
||||
* - Re-registering the same id overwrites the previous entry ("last wins").
|
||||
* - ClassId must be hashable (std::hash<ClassId> specialization must exist).
|
||||
*
|
||||
* @tparam ClassId -Unique class identifier type (e.g. std::string, int, enum).
|
||||
* @tparam BaseClass -Base type for all created objects.
|
||||
* @tparam Arg - Constructor arguments forwarded to registered derived types (by value).
|
||||
* @tparam ClassId Unique class identifier type (e.g. std::string, int, enum).
|
||||
* @tparam BaseClass Base type for all created objects.
|
||||
* @tparam Args Constructor arguments forwarded to registered derived types (by value).
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
@@ -58,20 +58,22 @@
|
||||
template<class ClassId, class BaseClass, class... Args>
|
||||
class TypeFactory {
|
||||
public:
|
||||
/** @brief Shared ownership handle returned for created instances. */
|
||||
using BasePtr = std::shared_ptr<BaseClass>;
|
||||
/** @brief Registered creator function signature. */
|
||||
using CreatorFn = BasePtr (*)(Args...);
|
||||
|
||||
TypeFactory() = default;
|
||||
|
||||
/**
|
||||
* @brief Registers a Derived type under the given id.
|
||||
*
|
||||
* Requirements (checked at compile-time):
|
||||
* - Derived must inherit from BaseClass
|
||||
* - Derived must be constructible from Args...
|
||||
*
|
||||
* Re-registering the same id overwrites the previous entry ("last wins").
|
||||
*/
|
||||
* @brief Registers a Derived type under the given id.
|
||||
*
|
||||
* Requirements (checked at compile-time):
|
||||
* - Derived must inherit from BaseClass
|
||||
* - Derived must be constructible from Args...
|
||||
*
|
||||
* Re-registering the same id overwrites the previous entry ("last wins").
|
||||
*/
|
||||
template<class Derived>
|
||||
void registerType(const ClassId &id) {
|
||||
static_assert(std::is_base_of_v<BaseClass, Derived>,
|
||||
@@ -83,30 +85,30 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns creator function for the given id.
|
||||
* @throws std::out_of_range when id is not registered.
|
||||
*/
|
||||
* @brief Returns creator function for the given id.
|
||||
* @throws std::out_of_range when id is not registered.
|
||||
*/
|
||||
[[nodiscard]] CreatorFn creator(const ClassId &id) const {
|
||||
return classes.at(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates an instance for the given id using provided arguments.
|
||||
* @throws std::out_of_range when id is not registered.
|
||||
*/
|
||||
* @brief Creates an instance for the given id using provided arguments.
|
||||
* @throws std::out_of_range when id is not registered.
|
||||
*/
|
||||
[[nodiscard]] BasePtr create(const ClassId &id, Args... args) const {
|
||||
return creator(id)(std::move(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether an id is registered.
|
||||
*/
|
||||
* @brief Checks whether an id is registered.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const ClassId &id) const {
|
||||
return classes.find(id) != classes.end();
|
||||
}
|
||||
|
||||
protected:
|
||||
// Protected by design: derived factories may extend/inspect the registry.
|
||||
/** @brief Registered creators; accessible to derived factories. */
|
||||
std::unordered_map<ClassId, CreatorFn> classes;
|
||||
|
||||
private:
|
||||
|
||||
Reference in new issue
Block a user