diff --git a/include/dbcppp/Iterator.h b/include/dbcppp/Iterator.h index 916761b..6cffc91 100644 --- a/include/dbcppp/Iterator.h +++ b/include/dbcppp/Iterator.h @@ -1,102 +1,174 @@ - #pragma once -#include +#include namespace dbcppp { - template - class Iterator + template + class Iterator final { public: - using self_t = Iterator; + using self_t = Iterator; using iterator_category = std::random_access_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = T; - using pointer = const value_type*; - using reference = const value_type&; - using get_t = std::function; + using pointer = value_type*; + using reference = value_type&; - Iterator(get_t get, std::size_t i) - : _get(get) + constexpr Iterator(P parent, F get, difference_type i) noexcept + : _parent(parent) + , _get(std::move(get)) , _i(i) {} - reference operator*() const + inline reference operator*() const + { + return (_parent->*_get)(static_cast(_i)); + } + inline pointer operator->() const { - return _get(_i); + return &(_parent->*_get)(static_cast(_i)); } - pointer operator->() const + inline reference operator[](difference_type o) const { - return &_get(_i); + return *(*this + o); } - self_t& operator++() + constexpr self_t& operator++() noexcept { - _i++; + ++_i; return *this; } - self_t operator+(std::size_t o) + constexpr self_t& operator--() noexcept { - return {_get, _i + o}; + --_i; + return *this; } - self_t operator-(std::size_t o) + constexpr self_t operator++(int) noexcept { - return {_get, _i + o}; + self_t old = *this; + ++_i; + return std::move(old); } - difference_type operator-(const self_t& rhs) + constexpr self_t operator--(int) noexcept + { + self_t old = *this; + --_i; + return std::move(old); + } + constexpr self_t operator+(difference_type o) const noexcept + { + return {_parent, _get, _i + o}; + } + constexpr self_t operator-(difference_type o) const noexcept + { + return {_parent, _get, _i - o}; + } + constexpr difference_type operator-(const self_t& rhs) const noexcept { return _i - rhs._i; } - self_t& operator+=(std::size_t o) + constexpr self_t& operator+=(difference_type o) noexcept { _i += o; return *this; } - self_t& operator-=(std::size_t o) + constexpr self_t& operator-=(difference_type o) noexcept { _i -= o; return *this; } - bool operator==(const self_t& rhs) const + constexpr bool operator==(const self_t& rhs) const noexcept { return _i == rhs._i; } - bool operator!=(const self_t& rhs) const + constexpr bool operator!=(const self_t& rhs) const noexcept { return !(*this == rhs); } + constexpr bool operator<(const self_t& rhs) const noexcept + { + return _i < rhs._i; + } + constexpr bool operator>(const self_t& rhs) const noexcept + { + return _i > rhs._i; + } + constexpr bool operator<=(const self_t& rhs) const noexcept + { + return _i <= rhs._i; + } + constexpr bool operator>=(const self_t& rhs) const noexcept + { + return _i >= rhs._i; + } private: - get_t _get; - std::size_t _i; + P _parent; + F _get; + difference_type _i; }; - template - class Iterable + template + class Iterable final { public: - Iterable(Iterator begin, Iterator end) - : _begin(begin) - , _end(end) + using value_type = const T; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = Iterator; + using const_iterator = Iterator; + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; + + constexpr Iterable(P parent, F get, size_t size) noexcept + : _parent(std::move(parent)) + , _get(std::move(get)) + , _size(std::move(size)) {} - Iterator& begin() + inline reference operator[](std::size_t o) const + { + return (_parent->*_get)(o); + } + constexpr iterator begin() noexcept + { + return iterator(_parent, _get, 0); + } + constexpr iterator end() noexcept + { + return iterator(_parent, _get, _size); + } + constexpr const_iterator cbegin() const noexcept + { + return const_iterator(_parent, _get, 0); + } + constexpr const_iterator cend() const noexcept + { + return const_iterator(_parent, _get, static_cast(_size)); + } + constexpr const_iterator begin() const noexcept + { + return cbegin(); + } + constexpr const_iterator end() const noexcept + { + return cend(); + } + constexpr size_type size() const noexcept { - return _begin; + return _size; } - Iterator& end() + constexpr bool empty() const noexcept { - return _end; + return _size == 0; } private: - Iterator _begin; - Iterator _end; + P _parent; + F _get; + size_t _size; }; } -#define DBCPPP_MAKE_ITERABLE(ClassName, Name, Type) \ - auto Name() const \ - { \ - auto get = std::bind(&ClassName::Name##_Get, this, std::placeholders::_1); \ - Iterator begin(get, 0); \ - Iterator end(get, Name##_Size()); \ - return Iterable(begin, end); \ +#define DBCPPP_MAKE_ITERABLE(ClassName, Name, Type) \ + inline Iterable Name() const noexcept \ + { \ + return {this, &ClassName::Name##_Get, Name##_Size()}; \ } diff --git a/include/dbcppp/Message.h b/include/dbcppp/Message.h index bbdeef0..b1228e9 100644 --- a/include/dbcppp/Message.h +++ b/include/dbcppp/Message.h @@ -50,6 +50,9 @@ namespace dbcppp virtual const std::string& Comment() const = 0; virtual const ISignalGroup& SignalGroups_Get(std::size_t i) const = 0; virtual uint64_t SignalGroups_Size() const = 0; + /// \brief Optional multiplexor signal when this message is using simple multiplexing with a single switch. + /// + /// For advanced multiplexing support, ISignal::SignalMultiplexerValues needs to be followed instead. virtual const ISignal* MuxSignal() const = 0; DBCPPP_MAKE_ITERABLE(IMessage, MessageTransmitters, std::string); diff --git a/include/dbcppp/Signal.h b/include/dbcppp/Signal.h index 7097a84..514ef18 100644 --- a/include/dbcppp/Signal.h +++ b/include/dbcppp/Signal.h @@ -29,7 +29,12 @@ namespace dbcppp }; enum class EMultiplexer { - NoMux, MuxSwitch, MuxValue + NoMux, + MuxSwitch = 1, + MuxValue = 2, + // For advanced multiplexing with ISignalMultiplexerValue, nesting is possible. + // This results in signals being both a multiplexor switch and a multiplexed value. + MuxSwitchAndValue = MuxSwitch | MuxValue }; enum class EByteOrder { @@ -44,7 +49,7 @@ namespace dbcppp { Integer, Float, Double }; - + static std::unique_ptr Create( uint64_t message_size , std::string&& name @@ -65,13 +70,21 @@ namespace dbcppp , std::string&& comment , EExtendedValueType extended_value_type , std::vector>&& signal_multiplexer_values); - + virtual std::unique_ptr Clone() const = 0; virtual ~ISignal() = default; virtual const std::string& Name() const = 0; virtual EMultiplexer MultiplexerIndicator() const = 0; + /// \brief Single multiplexor value for simple multiplexing. + /// + /// Invalid if ISignal::SignalMultiplexerValues is not empty. virtual uint64_t MultiplexerSwitchValue() const = 0; + /// \brief Least significant bit of the signal. + /// + /// \note DBC uses the least signficant bit as start bit for both big and little endian. + /// This means that for big endian, the StartBit points into the highest byte. + /// This differs from FIBEX/Autosar where big endian signals are instead using the least significant bit in the lowest byte as offset. virtual uint64_t StartBit() const = 0; virtual uint64_t BitSize() const = 0; virtual EByteOrder ByteOrder() const = 0; @@ -121,6 +134,12 @@ namespace dbcppp DBCPPP_MAKE_ITERABLE(ISignal, Receivers, std::string); DBCPPP_MAKE_ITERABLE(ISignal, ValueEncodingDescriptions, IValueEncodingDescription); DBCPPP_MAKE_ITERABLE(ISignal, AttributeValues, IAttribute); + + /// \brief Mapping of this multiplexed signal to specific value ranges of a selected multiplexor switch signals. + /// + /// Requires EMultiplexer::MuxValue to be set in MultiplexerIndicator in order to be valid. + /// If empty, simple multiplexing rules by ISignal::MultiplexerSwitchValue and IMessage::MuxSignal apply instead. + /// If not empty, all listed multiplexor signals must match the specified value ranges simultaniously. DBCPPP_MAKE_ITERABLE(ISignal, SignalMultiplexerValues, ISignalMultiplexerValue); protected: diff --git a/include/dbcppp/SignalMultiplexerValue.h b/include/dbcppp/SignalMultiplexerValue.h index 2779076..763c810 100644 --- a/include/dbcppp/SignalMultiplexerValue.h +++ b/include/dbcppp/SignalMultiplexerValue.h @@ -6,12 +6,12 @@ #include #include #include -#include #include "Iterator.h" namespace dbcppp { + // Map from values of the multiplexor signal ISignalMultiplexerValue::SwitchName to the parent multiplexed ISignal. class ISignalMultiplexerValue { public: diff --git a/src/DBCAST2Network.cpp b/src/DBCAST2Network.cpp index b3aed05..33b302e 100644 --- a/src/DBCAST2Network.cpp +++ b/src/DBCAST2Network.cpp @@ -351,16 +351,20 @@ static auto getSignals(const G_Network& gnet, const G_Message& m, Cache const& c uint64_t multiplexer_switch_value = 0; if (s.multiplexer_indicator) { - auto m = *s.multiplexer_indicator; - if (m.substr(0, 1) == "M") + const auto& m = *s.multiplexer_indicator; + if (auto mux_value_pos = m.find('m', 0); mux_value_pos != std::string::npos) { - multiplexer_indicator = ISignal::EMultiplexer::MuxSwitch; + multiplexer_indicator = ISignal::EMultiplexer( + std::underlying_type_t(multiplexer_indicator) | + std::underlying_type_t(ISignal::EMultiplexer::MuxValue)); + multiplexer_switch_value = std::atoi(m.c_str() + mux_value_pos + 1); } - else + if (m.find('M', 0) != std::string::npos) { - multiplexer_indicator = ISignal::EMultiplexer::MuxValue; - std::string value = m.substr(1, m.size()); - multiplexer_switch_value = std::atoi(value.c_str()); + multiplexer_indicator = + ISignal::EMultiplexer( + std::underlying_type_t(multiplexer_indicator) | + std::underlying_type_t(ISignal::EMultiplexer::MuxSwitch)); } } diff --git a/src/MessageImpl.cpp b/src/MessageImpl.cpp index 8ed225d..c04e354 100644 --- a/src/MessageImpl.cpp +++ b/src/MessageImpl.cpp @@ -67,22 +67,68 @@ MessageImpl::MessageImpl( , _mux_signal(nullptr) , _error(EErrorCode::NoError) { - bool have_mux_value = false; + bool have_mux_values = false; + size_t num_mux_switches = 0; + bool have_mux_values_without_advanced_mapping = false; for (const auto& sig : _signals) { - switch (sig.MultiplexerIndicator()) + if (std::underlying_type_t(sig.MultiplexerIndicator()) & + std::underlying_type_t(ISignal::EMultiplexer::MuxValue)) { - case ISignal::EMultiplexer::MuxValue: - have_mux_value = true; - break; - case ISignal::EMultiplexer::MuxSwitch: - _mux_signal = &sig; - break; + have_mux_values = true; + if (sig.SignalMultiplexerValues_Size() == 0) + { + have_mux_values_without_advanced_mapping = true; + } + else + { + for (const auto& multiplexor : sig.SignalMultiplexerValues()) + { + if (!std::any_of(_signals.begin(), _signals.end(), [&multiplexor](const SignalImpl& sig) + { return sig.Name() == multiplexor.SwitchName(); })) + { + _error = EErrorCode::MuxValeWithoutMuxSignal; + } + } + } + } + if (std::underlying_type_t(sig.MultiplexerIndicator()) & + std::underlying_type_t(ISignal::EMultiplexer::MuxSwitch)) + { + ++num_mux_switches; } } - if (have_mux_value && _mux_signal == nullptr) + if (num_mux_switches > 1) { - _error = EErrorCode::MuxValeWithoutMuxSignal; + if (have_mux_values_without_advanced_mapping) + { + _error = EErrorCode::MuxValeWithoutMuxSignal; + } + } + // MuxSignal property can be populated for simple multiplexing only. + else if (num_mux_switches == 1) + { + for (const auto& sig : _signals) + { + if (uint64_t(sig.MultiplexerIndicator()) & uint64_t(ISignal::EMultiplexer::MuxSwitch)) + { + _mux_signal = &sig; + } + } + for (const auto& sig : _signals) + { + if (uint64_t(sig.MultiplexerIndicator()) & uint64_t(ISignal::EMultiplexer::MuxValue)) + { + _mux_signal = &sig; + } + } + } + else if (num_mux_switches == 0) + { + if (have_mux_values) + { + _error = EErrorCode::MuxValeWithoutMuxSignal; + } } } MessageImpl::MessageImpl(const MessageImpl& other) diff --git a/src/Network2DBC.cpp b/src/Network2DBC.cpp index 62f32d8..8f8a845 100644 --- a/src/Network2DBC.cpp +++ b/src/Network2DBC.cpp @@ -499,10 +499,19 @@ DBCPPP_API std::ostream& dbcppp::Network2DBC::operator<<(std::ostream& os, const DBCPPP_API std::ostream& dbcppp::Network2DBC::operator<<(std::ostream& os, const ISignal& s) { os << "\tSG_ " << s.Name() << " "; - switch (s.MultiplexerIndicator()) + if (s.MultiplexerIndicator() != ISignal::EMultiplexer::NoMux) { - case ISignal::EMultiplexer::MuxSwitch: os << "M "; break; - case ISignal::EMultiplexer::MuxValue: os << "m" << s.MultiplexerSwitchValue() << " "; break; + if (std::underlying_type_t(s.MultiplexerIndicator()) & + std::underlying_type_t(ISignal::EMultiplexer::MuxValue)) + { + os << "m" << s.MultiplexerSwitchValue(); + } + if (std::underlying_type_t(s.MultiplexerIndicator()) & + std::underlying_type_t(ISignal::EMultiplexer::MuxSwitch)) + { + os << "M"; + } + os << " "; } os << ": " << s.StartBit() << "|" << s.BitSize() << "@"; switch (s.ByteOrder()) diff --git a/src/SignalImpl.cpp b/src/SignalImpl.cpp index b763395..706962d 100644 --- a/src/SignalImpl.cpp +++ b/src/SignalImpl.cpp @@ -612,11 +612,11 @@ uint64_t SignalImpl::SignalMultiplexerValues_Size() const } bool SignalImpl::Error(EErrorCode code) const { - return code == _error || (uint64_t(_error) & uint64_t(code)); + return code == _error || (std::underlying_type_t(_error) & std::underlying_type_t(code)); } void SignalImpl::SetError(EErrorCode code) { - _error = EErrorCode(uint64_t(_error) | uint64_t(code)); + _error = EErrorCode(std::underlying_type_t(_error) | std::underlying_type_t(code)); } bool SignalImpl::operator==(const ISignal& rhs) const {