Closes #10
This commit is contained in:
1 parent
a533d9aa00
commit
a0938cb29c
14 files changed
+375
-13
No files matched your search
@@ -169,9 +169,24 @@ SignalInfo DbcSignalHandler::ParseSignalLine(const std::string &line) {
|
||||
throw std::runtime_error("Malformed or unsupported SG_ signal definition.");
|
||||
|
||||
SignalInfo signal;
|
||||
signal.name = TrimText(fields[1].str());
|
||||
if (signal.name.empty() || signal.name.find_first_of(" \t\r\n") != std::string::npos)
|
||||
throw std::runtime_error("Invalid signal name or unsupported multiplexing syntax.");
|
||||
std::istringstream nameFields(fields[1].str());
|
||||
std::string marker;
|
||||
std::string extra;
|
||||
nameFields >> signal.name >> marker;
|
||||
if (signal.name.empty() || (nameFields >> extra))
|
||||
throw std::runtime_error("Invalid signal name or multiplexing marker.");
|
||||
if (marker == "M")
|
||||
signal.multiplexing.role = MultiplexRole::Selector;
|
||||
else if (!marker.empty()) {
|
||||
if (marker[0] != 'm')
|
||||
throw std::runtime_error("Unsupported multiplexing marker.");
|
||||
const std::string value = marker.substr(1U);
|
||||
const std::from_chars_result parsed = std::from_chars(
|
||||
value.data(), value.data() + value.size(), signal.multiplexing.value);
|
||||
if (value.empty() || parsed.ec != std::errc() || parsed.ptr != value.data() + value.size())
|
||||
throw std::runtime_error("Invalid or unsupported multiplexing marker.");
|
||||
signal.multiplexing.role = MultiplexRole::Branch;
|
||||
}
|
||||
|
||||
signal.startBit = ParseDecimal(fields[2].str(),
|
||||
std::numeric_limits<std::uint32_t>::max(), "signal start bit");
|
||||
@@ -281,6 +296,7 @@ namespace {
|
||||
void DbcFrameHandler::Handle(const std::string &line, DbcParseContext &context) const {
|
||||
context.database.frames.push_back(ParseFrameLine(line));
|
||||
context.currentFrame = &context.database.frames.back();
|
||||
context.signalLines.emplace_back();
|
||||
}
|
||||
|
||||
void DbcSignalHandler::Handle(const std::string &line, DbcParseContext &context) const {
|
||||
@@ -298,6 +314,7 @@ void DbcSignalHandler::Handle(const std::string &line, DbcParseContext &context)
|
||||
bit = (bit % 8U == 0U) ? bit + 15U : bit - 1U;
|
||||
}
|
||||
context.currentFrame->signals.push_back(std::move(signal));
|
||||
context.signalLines.back().push_back(context.lineNumber);
|
||||
}
|
||||
|
||||
void DbcCommentHandler::Handle(const std::string &line, DbcParseContext &context) const {
|
||||
@@ -306,6 +323,7 @@ void DbcCommentHandler::Handle(const std::string &line, DbcParseContext &context
|
||||
}
|
||||
|
||||
DbcStatementDispatcher::DbcStatementDispatcher() {
|
||||
RegisterType<DbcUnsupportedMultiplexingHandler>("SG_MUL_VAL_");
|
||||
RegisterType<DbcFrameHandler>("BO_");
|
||||
RegisterType<DbcSignalHandler>("SG_");
|
||||
RegisterType<DbcCommentHandler>("CM_");
|
||||
@@ -408,3 +426,70 @@ void DbcParseContext::ResolveValueDescriptions(const std::string &filePath) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DbcUnsupportedMultiplexingHandler::Handle(const std::string &, DbcParseContext &) const {
|
||||
throw std::runtime_error("Extended and nested multiplexing are unsupported.");
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::vector<std::uint64_t> SignalBits(const SignalInfo &signal) {
|
||||
std::vector<std::uint64_t> bits;
|
||||
std::uint64_t bit = signal.startBit;
|
||||
for (std::uint32_t index = 0U; index < signal.length; ++index) {
|
||||
bits.push_back(bit);
|
||||
if (signal.isLittleEndian)
|
||||
++bit;
|
||||
else
|
||||
bit = bit % 8U == 0U ? bit + 15U : bit - 1U;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
bool SignalsOverlap(const SignalInfo &first, const SignalInfo &second) {
|
||||
const std::vector<std::uint64_t> firstBits = SignalBits(first);
|
||||
const std::vector<std::uint64_t> secondBits = SignalBits(second);
|
||||
for (const std::uint64_t firstBit : firstBits) {
|
||||
for (const std::uint64_t secondBit : secondBits) {
|
||||
if (firstBit == secondBit)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DbcParseContext::ValidateMultiplexing(const std::string &filePath) const {
|
||||
for (std::size_t frameIndex = 0U; frameIndex < database.frames.size(); ++frameIndex) {
|
||||
const FrameInfo &frame = database.frames[frameIndex];
|
||||
const SignalInfo *selector = nullptr;
|
||||
for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
|
||||
const SignalInfo &signal = frame.signals[index];
|
||||
if (signal.multiplexing.role != MultiplexRole::Selector)
|
||||
continue;
|
||||
if (selector != nullptr || signal.isSigned)
|
||||
throw std::runtime_error(filePath + ":" + std::to_string(signalLines[frameIndex][index]) +
|
||||
": Multiplexing requires one unsigned selector per frame.");
|
||||
selector = &signal;
|
||||
}
|
||||
for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
|
||||
const SignalInfo &signal = frame.signals[index];
|
||||
std::string error;
|
||||
if (signal.multiplexing.role == MultiplexRole::Branch) {
|
||||
if (selector == nullptr)
|
||||
error = "Multiplexed branch has no selector.";
|
||||
else if (selector->length < 64U && signal.multiplexing.value >= (std::uint64_t(1U) << selector->length))
|
||||
error = "Branch value exceeds selector raw range.";
|
||||
}
|
||||
for (std::size_t previous = 0U; previous < index && error.empty(); ++previous) {
|
||||
const SignalInfo &other = frame.signals[previous];
|
||||
const bool exclusive = signal.multiplexing.role == MultiplexRole::Branch &&
|
||||
other.multiplexing.role == MultiplexRole::Branch &&
|
||||
signal.multiplexing.value != other.multiplexing.value;
|
||||
if (!exclusive && SignalsOverlap(signal, other))
|
||||
error = "Signals overlap without mutually exclusive multiplexing conditions.";
|
||||
}
|
||||
if (!error.empty())
|
||||
throw std::runtime_error(filePath + ":" + std::to_string(signalLines[frameIndex][index]) + ": " + error);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user