6#include "multiplex_graph.h"
7#include "signal_layout.h"
12#include <unordered_set>
15 constexpr std::size_t MaximumPayloadBits = std::numeric_limits<std::uint8_t>::max() * 8U;
16 using SignalBits = std::bitset<MaximumPayloadBits>;
18 void ValidateSignal(
const DecodeSignal &signal, std::uint8_t dlc) {
20 throw std::invalid_argument(
"Invalid signal byte order: " + signal.
name);
22 throw std::invalid_argument(
"Invalid signal value type: " + signal.
name);
23 if (signal.
multiplexing.role != MultiplexRole::Unconditional &&
26 signal.
multiplexing.role != MultiplexRole::BranchSelector)
27 throw std::invalid_argument(
"Invalid multiplexing role: " + signal.
name);
29 signal.
byteOrder == ByteOrder::Intel, dlc))
30 throw std::invalid_argument(
"Invalid signal length or payload position: " + signal.
name);
31 if (!std::isfinite(signal.
factor) || !std::isfinite(signal.
offset) ||
32 !std::isfinite(signal.
minimum) || !std::isfinite(signal.
maximum) ||
34 throw std::invalid_argument(
"Invalid signal numeric parameters: " + signal.
name);
39 const bool littleEndian = signal.
byteOrder == ByteOrder::Intel;
40 const std::uint64_t start = SignalStartCoordinate(signal.
startBit, littleEndian);
41 for (std::uint32_t index = 0U; index < signal.
length; ++index) {
42 const std::uint64_t coordinate = start + index;
43 const std::uint64_t bit = littleEndian ? coordinate
44 : coordinate / 8U * 8U + 7U - coordinate % 8U;
45 bits.set(
static_cast<std::size_t
>(bit));
51 const std::uint32_t maximumId = frame.
isExtended ? 0x1FFFFFFFU : 0x7FFU;
52 if (frame.
canId > maximumId)
53 throw std::invalid_argument(
"Invalid normalized CAN ID: " + std::to_string(frame.
canId));
56 throw std::invalid_argument(
"Invalid J1939 PGN metadata: " + frame.
name);
58 std::unordered_set<std::string> names;
61 if (!names.insert(signal.
name).second)
62 throw std::invalid_argument(
"Duplicate runtime signal key: " + signal.
name);
63 ValidateSignal(signal, frame.
dlc);
65 throw std::invalid_argument(
"Multiplex selectors must be unsigned.");
69 std::vector<SignalBits> layouts;
70 layouts.reserve(frame.signals.size());
71 for (std::size_t index = 0U; index < frame.signals.size(); ++index) {
73 const SignalBits bits = GetSignalBits(signal);
74 for (std::size_t previous = 0U; previous < index; ++previous) {
75 if (!graph.AreMutuallyExclusive(index, previous) && (bits & layouts[previous]).any())
76 throw std::invalid_argument(
"Overlapping signals: " + signal.
name);
78 layouts.push_back(bits);
84DecodeDatabase::Storage::Storage(
const std::vector<DecodeFrame> &definitions)
85 : frames(definitions) {
87 std::unordered_set<FrameKey, FrameKeyHasher> keys;
88 keys.reserve(frames.size());
89 multiplexGraphs.reserve(frames.size());
91 multiplexGraphs.push_back(ValidateFrame(frame));
92 if (!keys.insert(frame.
GetKey()).second)
93 throw std::invalid_argument(
"Duplicate runtime frame key");
95 frameIndexByKey.reserve(frames.size());
96 for (std::size_t index = 0U; index < frames.size(); ++index) {
97 frameIndexByKey.emplace(frames[index].GetKey(), index);
98 if (frames[index].hasPgn)
99 frameIndicesByPgn[frames[index].pgn].push_back(index);
103DecodeDatabase::DecodeDatabase(
const std::vector<DecodeFrame> &frames)
104 : storage(std::make_shared<const Storage>(frames)) {
108 static const std::vector<DecodeFrame> empty;
109 return storage ? storage->frames : empty;
115 const std::unordered_map<FrameKey, std::size_t, FrameKeyHasher>::const_iterator it =
116 storage->frameIndexByKey.find(key);
117 if (it == storage->frameIndexByKey.end())
119 return std::shared_ptr<const DecodeFrame>(storage, &storage->frames[it->second]);
126 const std::unordered_map<std::uint32_t, std::vector<std::size_t>>::const_iterator it =
127 storage->frameIndicesByPgn.find(pgn);
128 if (it == storage->frameIndicesByPgn.end())
130 if (it->second.size() != 1U) {
134 result.
definition = std::shared_ptr<const DecodeFrame>(storage, &storage->frames[it->second[0]]);
139 const std::shared_ptr<const DecodeFrame> frame =
FindFrame(key.
frame);
144 return std::shared_ptr<const DecodeSignal>(frame, &signal);
150 return storage->multiplexGraphs[storage->frameIndexByKey.at(key)];
std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
Return an owning signal handle, or an empty handle for a missing key.
std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
const std::vector< DecodeFrame > & GetFrames() const
PgnLookupResult FindFrameByPgn(std::uint32_t pgn) const
Runtime definitions and immutable indexed database.
Runtime-ready frame definition.
FrameKey GetKey() const
Return the stable normalized frame identifier.
Runtime-ready signal definition.
Multiplexing multiplexing
Stable frame identifier: normalized CAN ID and frame type.
std::shared_ptr< const DecodeFrame > definition