DBC Framework
DBC parsing and CAN signal decoding framework
Loading...
Searching...
No Matches
multiplex_graph.h
1// SPDX-License-Identifier: MIT
2#ifndef MULTIPLEX_GRAPH_H
3#define MULTIPLEX_GRAPH_H
4
5#include "multiplexing.h"
6#include <cstddef>
7#include <stdexcept>
8
9namespace dbc_detail {
11 class MultiplexError : public std::invalid_argument {
12 public:
13 MultiplexError(std::size_t signalIndex, const std::string &message)
14 : std::invalid_argument(message), index(signalIndex) {}
15 std::size_t index;
16 };
17
20 public:
21 template<class Signal>
22 explicit MultiplexGraph(const std::vector<Signal> &signals)
23 : parents(signals.size(), signals.size()), ranges(signals.size()) {
24 const std::size_t count = signals.size();
25 for (std::size_t index = 0U; index < count; ++index) {
26 const Multiplexing &mux = signals[index].multiplexing;
27 if (mux.role != MultiplexRole::Unconditional && mux.role != MultiplexRole::Selector &&
28 mux.role != MultiplexRole::Branch && mux.role != MultiplexRole::BranchSelector)
29 throw MultiplexError(index, "Invalid multiplexing role.");
30 if (mux.selector.empty() != mux.ranges.empty())
31 throw MultiplexError(index, "Selector name and ranges must be supplied together.");
32 if (mux.selector.empty() && !IsMultiplexBranch(mux.role))
33 continue;
34 std::size_t parent = count;
35 for (std::size_t candidate = 0U; candidate < count; ++candidate) {
36 const Multiplexing &other = signals[candidate].multiplexing;
37 const bool matches = !mux.selector.empty()
38 ? signals[candidate].name == mux.selector
39 : other.role == MultiplexRole::Selector && other.selector.empty();
40 if (!matches)
41 continue;
42 if (parent != count)
43 throw MultiplexError(index, "Ambiguous multiplex selector; use SG_MUL_VAL_.");
44 parent = candidate;
45 }
46 if (parent == count)
47 throw MultiplexError(index, "Multiplexed branch has no selector.");
48 if (!IsMultiplexSelector(signals[parent].multiplexing.role))
49 throw MultiplexError(index, "Referenced signal is not a multiplex selector.");
50 parents[index] = parent;
51 ranges[index] = mux.selector.empty() ? std::vector<MultiplexRange>{{mux.value, mux.value}} : mux.ranges;
52 for (const MultiplexRange &range: ranges[index]) {
53 if (range.minimum > range.maximum)
54 throw MultiplexError(index, "Reversed multiplex range.");
55 if (signals[parent].length < 64U && range.maximum >= (std::uint64_t(1U) << signals[parent].length))
56 throw MultiplexError(index, "Branch value exceeds selector raw range.");
57 }
58 }
59 for (std::size_t index = 0U; index < count; ++index) {
60 std::size_t current = index;
61 for (std::size_t depth = 0U; current != count; ++depth) {
62 if (depth >= count)
63 throw MultiplexError(index, "Cyclic multiplex selector dependency.");
64 current = parents[current];
65 }
66 }
67 }
68
69 bool Matches(std::size_t index, std::uint64_t value) const {
70 for (const MultiplexRange &range: ranges[index]) {
71 if (range.minimum <= value && value <= range.maximum)
72 return true;
73 }
74 return false;
75 }
76
77 bool AreMutuallyExclusive(std::size_t first, std::size_t second) const {
78 const std::size_t count = parents.size();
79 for (std::size_t left = first; parents[left] != count; left = parents[left]) {
80 for (std::size_t right = second; parents[right] != count; right = parents[right]) {
81 if (parents[left] != parents[right])
82 continue;
83 bool intersects = false;
84 for (const MultiplexRange &a: ranges[left]) {
85 for (const MultiplexRange &b: ranges[right]) {
86 if (a.minimum <= b.maximum && b.minimum <= a.maximum)
87 intersects = true;
88 }
89 }
90 if (!intersects)
91 return true;
92 }
93 }
94 return false;
95 }
96
97 std::vector<std::size_t> parents;
98 std::vector<std::vector<MultiplexRange>> ranges;
99 };
100}// namespace dbc_detail
101#endif
Inclusive raw selector range, without expanding individual values.
Basic markers and optional explicit extended multiplexing condition.
std::uint64_t value
std::vector< MultiplexRange > ranges
std::string selector