Skip to content

Commit d6b632f

Browse files
author
Andreas Ringlstetter
committed
Extend ISignal::EMultiplexer, validation for advanced multiplexing, documentation
1 parent a54c321 commit d6b632f

File tree

7 files changed

+125
-27
lines changed

7 files changed

+125
-27
lines changed

include/dbcppp/Message.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ namespace dbcppp
5050
virtual const std::string& Comment() const = 0;
5151
virtual const ISignalGroup& SignalGroups_Get(std::size_t i) const = 0;
5252
virtual uint64_t SignalGroups_Size() const = 0;
53+
/// \brief Optional multiplexor signal when this message is using simple multiplexing with a single switch.
54+
///
55+
/// For advanced multiplexing support, ISignal::SignalMultiplexerValues needs to be followed instead.
5356
virtual const ISignal* MuxSignal() const = 0;
5457

5558
DBCPPP_MAKE_ITERABLE(IMessage, MessageTransmitters, std::string);

include/dbcppp/Signal.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,17 @@ namespace dbcppp
2525
MaschinesFloatEncodingNotSupported = 1,
2626
MaschinesDoubleEncodingNotSupported = 2,
2727
SignalExceedsMessageSize = 4,
28-
WrongBitSizeForExtendedDataType = 8
28+
WrongBitSizeForExtendedDataType = 8,
29+
ConflictingMultiplexDefinition = 16,
2930
};
3031
enum class EMultiplexer
3132
{
32-
NoMux, MuxSwitch, MuxValue
33+
NoMux,
34+
MuxSwitch = 1,
35+
MuxValue = 2,
36+
// For advanced multiplexing with ISignalMultiplexerValue, nesting is possible.
37+
// This results in signals being both a multiplexor switch and a multiplexed value.
38+
MuxSwitchAndValue = MuxSwitch | MuxValue
3339
};
3440
enum class EByteOrder
3541
{
@@ -44,7 +50,7 @@ namespace dbcppp
4450
{
4551
Integer, Float, Double
4652
};
47-
53+
4854
static std::unique_ptr<ISignal> Create(
4955
uint64_t message_size
5056
, std::string&& name
@@ -65,13 +71,21 @@ namespace dbcppp
6571
, std::string&& comment
6672
, EExtendedValueType extended_value_type
6773
, std::vector<std::unique_ptr<ISignalMultiplexerValue>>&& signal_multiplexer_values);
68-
74+
6975
virtual std::unique_ptr<ISignal> Clone() const = 0;
7076

7177
virtual ~ISignal() = default;
7278
virtual const std::string& Name() const = 0;
7379
virtual EMultiplexer MultiplexerIndicator() const = 0;
80+
/// \brief Single multiplexor value for simple multiplexing.
81+
///
82+
/// Invalid if ISignal::SignalMultiplexerValues is not empty.
7483
virtual uint64_t MultiplexerSwitchValue() const = 0;
84+
/// \brief Least significant bit of the signal.
85+
///
86+
/// \note DBC uses the least signficant bit as start bit for both big and little endian.
87+
/// This means that for big endian, the StartBit points into the highest byte.
88+
/// This differs from FIBEX/Autosar where big endian signals are instead using the least significant bit in the lowest byte as offset.
7589
virtual uint64_t StartBit() const = 0;
7690
virtual uint64_t BitSize() const = 0;
7791
virtual EByteOrder ByteOrder() const = 0;
@@ -121,6 +135,12 @@ namespace dbcppp
121135
DBCPPP_MAKE_ITERABLE(ISignal, Receivers, std::string);
122136
DBCPPP_MAKE_ITERABLE(ISignal, ValueEncodingDescriptions, IValueEncodingDescription);
123137
DBCPPP_MAKE_ITERABLE(ISignal, AttributeValues, IAttribute);
138+
139+
/// \brief Mapping of this multiplexed signal to specific value ranges of a selected multiplexor switch signal.
140+
///
141+
/// In a valid DBC, this can only have 0 or 1 entries.
142+
/// Requires EMultiplexer::MuxValue to be set in MultiplexerIndicator in order to be valid.
143+
/// If empty, simple multiplexing rules by ISignal::MultiplexerSwitchValue and IMessage::MuxSignal apply instead.
124144
DBCPPP_MAKE_ITERABLE(ISignal, SignalMultiplexerValues, ISignalMultiplexerValue);
125145

126146
protected:

include/dbcppp/SignalMultiplexerValue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
#include <memory>
77
#include <vector>
88
#include <functional>
9-
#include <cstdint>
109

1110
#include "Iterator.h"
1211

1312
namespace dbcppp
1413
{
14+
// Map from values of the multiplexor signal ISignalMultiplexerValue::SwitchName to the parent multiplexed ISignal.
1515
class ISignalMultiplexerValue
1616
{
1717
public:

src/DBCAST2Network.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -351,16 +351,20 @@ static auto getSignals(const G_Network& gnet, const G_Message& m, Cache const& c
351351
uint64_t multiplexer_switch_value = 0;
352352
if (s.multiplexer_indicator)
353353
{
354-
auto m = *s.multiplexer_indicator;
355-
if (m.substr(0, 1) == "M")
354+
const auto& m = *s.multiplexer_indicator;
355+
if (auto mux_value_pos = m.find('m', 0); mux_value_pos != std::string::npos)
356356
{
357-
multiplexer_indicator = ISignal::EMultiplexer::MuxSwitch;
357+
multiplexer_indicator = ISignal::EMultiplexer(
358+
std::underlying_type_t<ISignal::EMultiplexer>(multiplexer_indicator) |
359+
std::underlying_type_t<ISignal::EMultiplexer>(ISignal::EMultiplexer::MuxValue));
360+
multiplexer_switch_value = std::atoi(m.c_str() + mux_value_pos + 1);
358361
}
359-
else
362+
if (m.find('M', 0) != std::string::npos)
360363
{
361-
multiplexer_indicator = ISignal::EMultiplexer::MuxValue;
362-
std::string value = m.substr(1, m.size());
363-
multiplexer_switch_value = std::atoi(value.c_str());
364+
multiplexer_indicator =
365+
ISignal::EMultiplexer(
366+
std::underlying_type_t<ISignal::EMultiplexer>(multiplexer_indicator) |
367+
std::underlying_type_t<ISignal::EMultiplexer>(ISignal::EMultiplexer::MuxSwitch));
364368
}
365369
}
366370

src/MessageImpl.cpp

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,22 +67,68 @@ MessageImpl::MessageImpl(
6767
, _mux_signal(nullptr)
6868
, _error(EErrorCode::NoError)
6969
{
70-
bool have_mux_value = false;
70+
bool have_mux_values = false;
71+
size_t num_mux_switches = 0;
72+
bool have_mux_values_without_advanced_mapping = false;
7173
for (const auto& sig : _signals)
7274
{
73-
switch (sig.MultiplexerIndicator())
75+
if (std::underlying_type_t<ISignal::EMultiplexer>(sig.MultiplexerIndicator()) &
76+
std::underlying_type_t<ISignal::EMultiplexer>(ISignal::EMultiplexer::MuxValue))
7477
{
75-
case ISignal::EMultiplexer::MuxValue:
76-
have_mux_value = true;
77-
break;
78-
case ISignal::EMultiplexer::MuxSwitch:
79-
_mux_signal = &sig;
80-
break;
78+
have_mux_values = true;
79+
if (sig.SignalMultiplexerValues_Size() == 0)
80+
{
81+
have_mux_values_without_advanced_mapping = true;
82+
}
83+
else
84+
{
85+
for (const auto& multiplexor : sig.SignalMultiplexerValues())
86+
{
87+
if (!std::any_of(_signals.begin(), _signals.end(), [&multiplexor](const SignalImpl& sig)
88+
{ return sig.Name() == multiplexor.SwitchName(); }))
89+
{
90+
_error = EErrorCode::MuxValeWithoutMuxSignal;
91+
}
92+
}
93+
}
94+
}
95+
if (std::underlying_type_t<ISignal::EMultiplexer>(sig.MultiplexerIndicator()) &
96+
std::underlying_type_t<ISignal::EMultiplexer>(ISignal::EMultiplexer::MuxSwitch))
97+
{
98+
++num_mux_switches;
8199
}
82100
}
83-
if (have_mux_value && _mux_signal == nullptr)
101+
if (num_mux_switches > 1)
84102
{
85-
_error = EErrorCode::MuxValeWithoutMuxSignal;
103+
if (have_mux_values_without_advanced_mapping)
104+
{
105+
_error = EErrorCode::MuxValeWithoutMuxSignal;
106+
}
107+
}
108+
// MuxSignal property can be populated for simple multiplexing only.
109+
else if (num_mux_switches == 1)
110+
{
111+
for (const auto& sig : _signals)
112+
{
113+
if (uint64_t(sig.MultiplexerIndicator()) & uint64_t(ISignal::EMultiplexer::MuxSwitch))
114+
{
115+
_mux_signal = &sig;
116+
}
117+
}
118+
for (const auto& sig : _signals)
119+
{
120+
if (uint64_t(sig.MultiplexerIndicator()) & uint64_t(ISignal::EMultiplexer::MuxValue))
121+
{
122+
_mux_signal = &sig;
123+
}
124+
}
125+
}
126+
else if (num_mux_switches == 0)
127+
{
128+
if (have_mux_values)
129+
{
130+
_error = EErrorCode::MuxValeWithoutMuxSignal;
131+
}
86132
}
87133
}
88134
MessageImpl::MessageImpl(const MessageImpl& other)

src/Network2DBC.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -499,10 +499,19 @@ DBCPPP_API std::ostream& dbcppp::Network2DBC::operator<<(std::ostream& os, const
499499
DBCPPP_API std::ostream& dbcppp::Network2DBC::operator<<(std::ostream& os, const ISignal& s)
500500
{
501501
os << "\tSG_ " << s.Name() << " ";
502-
switch (s.MultiplexerIndicator())
502+
if (s.MultiplexerIndicator() != ISignal::EMultiplexer::NoMux)
503503
{
504-
case ISignal::EMultiplexer::MuxSwitch: os << "M "; break;
505-
case ISignal::EMultiplexer::MuxValue: os << "m" << s.MultiplexerSwitchValue() << " "; break;
504+
if (std::underlying_type_t<ISignal::EMultiplexer>(s.MultiplexerIndicator()) &
505+
std::underlying_type_t<ISignal::EMultiplexer>(ISignal::EMultiplexer::MuxValue))
506+
{
507+
os << "m" << s.MultiplexerSwitchValue();
508+
}
509+
if (std::underlying_type_t<ISignal::EMultiplexer>(s.MultiplexerIndicator()) &
510+
std::underlying_type_t<ISignal::EMultiplexer>(ISignal::EMultiplexer::MuxSwitch))
511+
{
512+
os << "M";
513+
}
514+
os << " ";
506515
}
507516
os << ": " << s.StartBit() << "|" << s.BitSize() << "@";
508517
switch (s.ByteOrder())

src/SignalImpl.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,22 @@ SignalImpl::SignalImpl(
517517
_phys_to_raw = ::phys_to_raw<double>;
518518
break;
519519
}
520+
// Permitted due to faulty interface design in ISignal only - doesn't happen with real DBC files.
521+
if (_signal_multiplexer_values.size() > 1)
522+
{
523+
SetError(EErrorCode::ConflictingMultiplexDefinition);
524+
}
525+
else if (_signal_multiplexer_values.size() == 1)
526+
{
527+
const auto ranges = _signal_multiplexer_values[0].ValueRanges();
528+
if (!std::any_of(std::begin(ranges), std::end(ranges), [&](const ISignalMultiplexerValue::Range& range) -> bool
529+
{
530+
return range.from <= _multiplexer_switch_value && range.to >= _multiplexer_switch_value;
531+
}))
532+
{
533+
SetError(EErrorCode::ConflictingMultiplexDefinition);
534+
}
535+
}
520536
}
521537
std::unique_ptr<ISignal> SignalImpl::Clone() const
522538
{
@@ -612,11 +628,11 @@ uint64_t SignalImpl::SignalMultiplexerValues_Size() const
612628
}
613629
bool SignalImpl::Error(EErrorCode code) const
614630
{
615-
return code == _error || (uint64_t(_error) & uint64_t(code));
631+
return code == _error || (std::underlying_type_t<EErrorCode>(_error) & std::underlying_type_t<EErrorCode>(code));
616632
}
617633
void SignalImpl::SetError(EErrorCode code)
618634
{
619-
_error = EErrorCode(uint64_t(_error) | uint64_t(code));
635+
_error = EErrorCode(std::underlying_type_t<EErrorCode>(_error) | std::underlying_type_t<EErrorCode>(code));
620636
}
621637
bool SignalImpl::operator==(const ISignal& rhs) const
622638
{

0 commit comments

Comments
 (0)