DBC Framework
DBC parsing and CAN signal decoding framework
Loading...
Searching...
No Matches
dbc_pipeline_test.cpp
2#include "dbc_decoder.h"
3#include "dbc_parser.h"
4#include "dbc_tree_builder.h"
5#include <QTemporaryFile>
6#include <QtTest>
7#include <stdexcept>
8#include <utility>
9
10namespace {
11 const std::string fixture = R"DBC(BO_ 291 Standard: 2 SenderA
12 SG_ Mode M : 0|8@1+ (1,0) [0|255] "" ReceiverA
13 SG_ State m3 : 8|8@1+ (2,1) [1|511] "km/h" ReceiverA,ReceiverB
14BO_ 2147483939 Extended: 1 SenderB
15 SG_ State : 7|8@0- (0.5,-3) [-67|60.5] "deg C" ReceiverB
16BO_ 2565866562 J1939: 0 SenderC
17CM_ BO_ 291 "Standard frame comment";
18CM_ SG_ 291 Mode "Selector comment";
19CM_ SG_ 291 State "Standard signal comment";
20CM_ BO_ 2147483939 "Extended frame comment";
21CM_ SG_ 2147483939 State "Extended signal comment";
22VAL_ 291 Mode 3 "Selected";
23VAL_ 291 State 4 "Standard four";
24VAL_ 2147483939 State -2 "Extended minus two";
25)DBC";
26
27 DbcParseResult ParseFixture(const std::string &text) {
28 QTemporaryFile file;
29 if (!file.open()) throw std::runtime_error("Cannot create DBC fixture");
30 if (file.write(text.data(), static_cast<qint64>(text.size())) != static_cast<qint64>(text.size()) || !file.flush())
31 throw std::runtime_error("Cannot write DBC fixture");
32 return DbcParser(DbcParserOptions{true}).ParseFileWithDiagnostics(file.fileName().toStdString());
33 }
34
35 // Independent expectations ensure a parser regression cannot be hidden by
36 // comparing builders only with the same incorrect parsed input.
37 DbcDatabase ExpectedMetadata() {
38 FrameInfo standard;
39 standard.name = "Standard";
40 standard.canId = 291U;
41 standard.dlc = 2U;
42 standard.transmitter = "SenderA";
43 standard.comment = "Standard frame comment";
44 SignalInfo mode;
45 mode.name = "Mode";
46 mode.multiplexing.role = MultiplexRole::Selector;
47 mode.length = 8U;
48 mode.maximum = 255;
49 mode.receivers = {"ReceiverA"};
50 mode.comment = "Selector comment";
51 mode.valueDescriptions = {{std::uint64_t(3), "Selected"}};
52 SignalInfo state;
53 state.name = "State";
54 state.multiplexing.role = MultiplexRole::Branch;
55 state.multiplexing.value = 3U;
56 state.startBit = 8U;
57 state.length = 8U;
58 state.factor = 2;
59 state.offset = 1;
60 state.minimum = 1;
61 state.maximum = 511;
62 state.unit = "km/h";
63 state.receivers = {"ReceiverA", "ReceiverB"};
64 state.comment = "Standard signal comment";
65 state.valueDescriptions = {{std::uint64_t(4), "Standard four"}};
66 standard.signals = {mode, state};
67
68 FrameInfo extended;
69 extended.name = "Extended";
70 extended.canId = 291U;
71 extended.isExtended = true;
72 extended.hasPgn = true;
73 extended.dlc = 1U;
74 extended.transmitter = "SenderB";
75 extended.comment = "Extended frame comment";
76 state.multiplexing = Multiplexing();
77 state.startBit = 7U;
78 state.isLittleEndian = false;
79 state.isSigned = true;
80 state.factor = 0.5;
81 state.offset = -3;
82 state.minimum = -67;
83 state.maximum = 60.5;
84 state.unit = "deg C";
85 state.receivers = {"ReceiverB"};
86 state.comment = "Extended signal comment";
87 state.valueDescriptions = {{std::int64_t(-2), "Extended minus two"}};
88 extended.signals = {state};
89
90 FrameInfo j1939;
91 j1939.name = "J1939";
92 j1939.canId = 0x18F00442U;
93 j1939.isExtended = true;
94 j1939.hasPgn = true;
95 j1939.pgn = 0xF004U;
96 j1939.transmitter = "SenderC";
97 return DbcDatabase{{standard, extended, j1939}};
98 }
99
100 template<class Signal>
101 void CheckSignalMetadata(const Signal &actual, const SignalInfo &expected) {
102 QCOMPARE(actual.name, expected.name);
103 QCOMPARE(actual.startBit, expected.startBit);
104 QCOMPARE(actual.length, expected.length);
105 QCOMPARE(actual.factor, expected.factor);
106 QCOMPARE(actual.offset, expected.offset);
107 QCOMPARE(actual.minimum, expected.minimum);
108 QCOMPARE(actual.maximum, expected.maximum);
109 QCOMPARE(actual.unit, expected.unit);
110 QVERIFY(actual.receivers == expected.receivers);
111 QCOMPARE(actual.comment, expected.comment);
112 QVERIFY(actual.valueDescriptions == expected.valueDescriptions);
113 QCOMPARE(actual.multiplexing.role, expected.multiplexing.role);
114 QCOMPARE(actual.multiplexing.value, expected.multiplexing.value);
115 }
116
117 void CheckSignal(const SignalInfo &actual, const SignalInfo &expected) {
118 CheckSignalMetadata(actual, expected);
119 QCOMPARE(actual.isLittleEndian, expected.isLittleEndian);
120 QCOMPARE(actual.isSigned, expected.isSigned);
121 }
122
123 void CheckSignal(const DecodeSignal &actual, const SignalInfo &expected) {
124 CheckSignalMetadata(actual, expected);
125 QCOMPARE(actual.byteOrder, expected.isLittleEndian ? ByteOrder::Intel : ByteOrder::Motorola);
126 QCOMPARE(actual.valueType, expected.isSigned ? ValueType::Signed : ValueType::Unsigned);
127 }
128
129 template<class Frame>
130 void CheckFrame(const Frame &actual, const FrameInfo &expected) {
131 QCOMPARE(actual.name, expected.name);
132 QCOMPARE(actual.canId, expected.canId);
133 QCOMPARE(actual.isExtended, expected.isExtended);
134 QCOMPARE(actual.dlc, expected.dlc);
135 QCOMPARE(actual.pgn, expected.pgn);
136 QCOMPARE(actual.hasPgn, expected.hasPgn);
137 QCOMPARE(actual.transmitter, expected.transmitter);
138 QCOMPARE(actual.comment, expected.comment);
139 QCOMPARE(actual.signals.size(), expected.signals.size());
140 for (std::size_t i = 0; i < expected.signals.size(); ++i)
141 CheckSignal(actual.signals[i], expected.signals[i]);
142 }
143
144 void CheckTree(const TreeNode &root, const DbcDatabase &expected) {
145 QCOMPARE(root.GetType(), NodeType::Root);
146 QVERIFY(root.GetParent() == nullptr);
147 QVERIFY(root.GetFrame() == nullptr);
148 QVERIFY(root.GetSignal() == nullptr);
149 QCOMPARE(root.GetChildCount(), expected.frames.size());
150 for (std::size_t i = 0; i < expected.frames.size(); ++i) {
151 const TreeNode *frame = root.GetChild(i);
152 QVERIFY(frame != nullptr);
153 QCOMPARE(frame->GetType(), NodeType::Frame);
154 QCOMPARE(frame->GetParent(), &root);
155 QCOMPARE(frame->GetRow(), i);
156 QCOMPARE(frame->GetName(), expected.frames[i].name);
157 QVERIFY(frame->GetFrame() != nullptr);
158 QVERIFY(frame->GetSignal() == nullptr);
159 CheckFrame(*frame->GetFrame(), expected.frames[i]);
160 QCOMPARE(frame->GetChildCount(), expected.frames[i].signals.size());
161 for (std::size_t j = 0; j < frame->GetChildCount(); ++j) {
162 const TreeNode *signal = frame->GetChild(j);
163 QVERIFY(signal != nullptr);
164 QCOMPARE(signal->GetType(), NodeType::Signal);
165 QCOMPARE(signal->GetParent(), frame);
166 QCOMPARE(signal->GetRow(), j);
167 QCOMPARE(signal->GetName(), expected.frames[i].signals[j].name);
168 QVERIFY(signal->GetSignal() != nullptr);
169 QVERIFY(signal->GetFrame() == nullptr);
170 QCOMPARE(signal->GetChildCount(), std::size_t(0));
171 CheckSignal(*signal->GetSignal(), expected.frames[i].signals[j]);
172 }
173 }
174 QVERIFY(root.GetChild(expected.frames.size()) == nullptr);
175 }
176
177 void CheckUnknown(const DecodeDatabase &runtime, bool extended) {
178 const FrameKey key(291U, extended);
179 QVERIFY(runtime.FindFrame(key) == nullptr);
180 QVERIFY(runtime.FindSignal(SignalKey(key, "State")) == nullptr);
181 QVERIFY(DbcDecoder().FindFrame(runtime, key.canId, key.isExtended) == nullptr);
182 RawCanFrame raw;
183 raw.canId = key.canId;
184 raw.isExtended = extended;
185 raw.data = {3U, 4U};
186 const DecodedFrameValue decoded = DbcDecoder().Decode(runtime, raw);
187 QVERIFY(!decoded.valid);
188 QCOMPARE(decoded.status, FrameDecodeStatus::UnknownFrame);
189 QVERIFY(decoded.definition == nullptr);
190 QVERIFY(decoded.signals.empty());
191 QVERIFY(decoded.key == key);
192 }
193}// namespace
194
195class PipelineTest : public QObject {
196 Q_OBJECT
197private Q_SLOTS:
198 void metadataLookupDecodeAndTree();
199 void emptyDatabase_data();
200 void emptyDatabase();
201 void databaseReplacement();
202};
203
204void PipelineTest::metadataLookupDecodeAndTree() {
205 const DbcParseResult parsed = ParseFixture(fixture);
206 QVERIFY(!parsed.HasErrors());
207 QVERIFY(parsed.diagnostics.empty());
208 const DbcDatabase expected = ExpectedMetadata();
209 QCOMPARE(parsed.database.frames.size(), expected.frames.size());
210 const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed.database);
211 QCOMPARE(runtime.GetFrames().size(), expected.frames.size());
212 const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed.database);
213 QVERIFY(tree != nullptr);
214 CheckTree(*tree, expected);
215 for (std::size_t i = 0; i < expected.frames.size(); ++i) {
216 CheckFrame(parsed.database.frames[i], expected.frames[i]);
217 CheckFrame(runtime.GetFrames()[i], expected.frames[i]);
218 const FrameKey key(expected.frames[i].canId, expected.frames[i].isExtended);
219 const std::shared_ptr<const DecodeFrame> found = runtime.FindFrame(key);
220 QVERIFY(found != nullptr);
221 QCOMPARE(found.get(), &runtime.GetFrames()[i]);
222 QCOMPARE(DbcDecoder().FindFrame(runtime, key.canId, key.isExtended).get(), found.get());
223 for (std::size_t j = 0; j < found->signals.size(); ++j) {
224 const std::shared_ptr<const DecodeSignal> signal = runtime.FindSignal(SignalKey(key, found->signals[j].name));
225 QVERIFY(signal != nullptr);
226 QCOMPARE(signal.get(), &found->signals[j]);
227 }
228 }
229 QVERIFY(runtime.FindSignal(SignalKey(FrameKey(291U, true), "Mode")) == nullptr);
230 QVERIFY(runtime.FindFrame(FrameKey(292U, false)) == nullptr);
231
232 RawCanFrame raw;
233 raw.canId = 291U;
234 raw.data = {3U, 4U};
235 const DecodedFrameValue standard = DbcDecoder().Decode(runtime, raw);
236 QVERIFY(standard.valid);
237 QCOMPARE(standard.status, FrameDecodeStatus::Valid);
238 QVERIFY(standard.key == FrameKey(291U, false));
239 QCOMPARE(standard.definition.get(), runtime.FindFrame(standard.key).get());
240 QCOMPARE(standard.signals.size(), std::size_t(2));
241 for (std::size_t i = 0; i < standard.signals.size(); ++i) {
242 const DecodedSignalValue &signal = standard.signals[i];
243 QVERIFY(signal.valid);
244 QCOMPARE(signal.status, SignalDecodeStatus::Valid);
245 QVERIFY(signal.key == SignalKey(standard.key, i == 0 ? "Mode" : "State"));
246 QCOMPARE(signal.definition.get(), runtime.FindSignal(signal.key).get());
247 QCOMPARE(std::get<std::uint64_t>(signal.rawValue), i == 0 ? 3U : 4U);
248 QCOMPARE(signal.physicalValue, i == 0 ? 3.0 : 9.0);
249 QVERIFY(signal.GetValueDescription() != nullptr);
250 QCOMPARE(*signal.GetValueDescription(), std::string(i == 0 ? "Selected" : "Standard four"));
251 }
252 raw.isExtended = true;
253 raw.data = {0xFEU};
254 const DecodedFrameValue extended = DbcDecoder().Decode(runtime, raw);
255 QVERIFY(extended.valid);
256 QCOMPARE(extended.status, FrameDecodeStatus::Valid);
257 QVERIFY(extended.key == FrameKey(291U, true));
258 QCOMPARE(extended.definition.get(), runtime.FindFrame(extended.key).get());
259 QCOMPARE(extended.signals.size(), std::size_t(1));
260 const DecodedSignalValue &signal = extended.signals[0];
261 QVERIFY(signal.valid);
262 QCOMPARE(signal.status, SignalDecodeStatus::Valid);
263 QVERIFY(signal.key == SignalKey(extended.key, "State"));
264 QCOMPARE(signal.definition.get(), runtime.FindSignal(signal.key).get());
265 QCOMPARE(std::get<std::int64_t>(signal.rawValue), std::int64_t(-2));
266 QCOMPARE(signal.physicalValue, -4.0);
267 QVERIFY(signal.GetValueDescription() != nullptr);
268 QCOMPARE(*signal.GetValueDescription(), std::string("Extended minus two"));
269
270 raw.canId = 0x18F00442U;
271 raw.data.clear();
272 const DecodedFrameValue j1939 = DbcDecoder().Decode(runtime, raw);
273 QVERIFY(j1939.valid);
274 QCOMPARE(j1939.status, FrameDecodeStatus::Valid);
275 QVERIFY(j1939.key == FrameKey(0x18F00442U, true));
276 QCOMPARE(j1939.definition.get(), runtime.FindFrame(j1939.key).get());
277 QVERIFY(j1939.signals.empty());
278}
279
280void PipelineTest::emptyDatabase_data() {
281 QTest::addColumn<QString>("text");
282 QTest::newRow("empty-file") << QString();
283 QTest::newRow("headers-only") << QString::fromUtf8("VERSION \"empty\"\nNS_ :\nBS_:\nBU_: Sender\n");
284}
285
286void PipelineTest::emptyDatabase() {
287 QFETCH(QString, text);
288 const DbcParseResult parsed = ParseFixture(text.toStdString());
289 QVERIFY(!parsed.HasErrors());
290 QVERIFY(parsed.diagnostics.empty());
291 QVERIFY(parsed.database.frames.empty());
292 const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed.database);
293 QVERIFY(runtime.GetFrames().empty());
294 CheckUnknown(runtime, false);
295 CheckUnknown(runtime, true);
296 const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed.database);
297 QVERIFY(tree != nullptr);
298 CheckTree(*tree, DbcDatabase());
299}
300
301void PipelineTest::databaseReplacement() {
302 DbcParseResult parsed = ParseFixture(fixture);
303 QVERIFY(!parsed.HasErrors());
304 DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed.database);
305 std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed.database);
306 RawCanFrame raw;
307 raw.canId = 291U;
308 raw.data = {3U, 4U};
309 const DecodedFrameValue saved = DbcDecoder().Decode(runtime, raw);
310 QVERIFY(saved.valid);
311 QCOMPARE(saved.signals.size(), std::size_t(2));
312 QVERIFY(tree != nullptr);
313 std::unique_ptr<TreeNode> savedTree = std::move(tree);
314
315 parsed = ParseFixture(R"DBC(BO_ 291 Replacement: 1 NewSender
316 SG_ NewState : 0|8@1+ (3,-1) [-1|764] "V" NewReceiver
317CM_ BO_ 291 "Replacement frame";
318CM_ SG_ 291 NewState "Replacement signal";
319VAL_ 291 NewState 4 "New four";
320)DBC");
321 QVERIFY(!parsed.HasErrors());
322 QVERIFY(parsed.diagnostics.empty());
323 FrameInfo replacement;
324 replacement.name = "Replacement";
325 replacement.canId = 291U;
326 replacement.dlc = 1U;
327 replacement.transmitter = "NewSender";
328 replacement.comment = "Replacement frame";
329 SignalInfo state;
330 state.name = "NewState";
331 state.length = 8U;
332 state.factor = 3;
333 state.offset = -1;
334 state.minimum = -1;
335 state.maximum = 764;
336 state.unit = "V";
337 state.receivers = {"NewReceiver"};
338 state.comment = "Replacement signal";
339 state.valueDescriptions = {{std::uint64_t(4), "New four"}};
340 replacement.signals = {state};
341 const DbcDatabase expected{{replacement}};
342 QCOMPARE(parsed.database.frames.size(), std::size_t(1));
343 CheckFrame(parsed.database.frames[0], replacement);
344 runtime = DbcDecodeBuilder().Build(parsed.database);
345 tree = DbcTreeBuilder().Build(parsed.database);
346 QVERIFY(tree != nullptr);
347 QCOMPARE(runtime.GetFrames().size(), std::size_t(1));
348 CheckFrame(runtime.GetFrames()[0], replacement);
349 CheckTree(*tree, expected);
350 CheckUnknown(runtime, true);
351 QVERIFY(runtime.FindFrame(FrameKey(0x18F00442U, true)) == nullptr);
352 QVERIFY(runtime.FindSignal(SignalKey(FrameKey(291U, false), "State")) == nullptr);
353 QVERIFY(runtime.FindSignal(SignalKey(FrameKey(291U, false), "Mode")) == nullptr);
354 raw.data = {4U};
355 const DecodedFrameValue current = DbcDecoder().Decode(runtime, raw);
356 QVERIFY(current.valid);
357 QCOMPARE(current.status, FrameDecodeStatus::Valid);
358 QCOMPARE(current.signals.size(), std::size_t(1));
359 QVERIFY(current.signals[0].valid);
360 QVERIFY(current.signals[0].key == SignalKey(FrameKey(291U, false), "NewState"));
361 QCOMPARE(current.signals[0].definition.get(), runtime.FindSignal(current.signals[0].key).get());
362 QCOMPARE(std::get<std::uint64_t>(current.signals[0].rawValue), std::uint64_t(4));
363 QCOMPARE(current.signals[0].physicalValue, 11.0);
364 QVERIFY(current.signals[0].GetValueDescription() != nullptr);
365 QCOMPARE(*current.signals[0].GetValueDescription(), std::string("New four"));
366
367 parsed = ParseFixture("");
368 QVERIFY(!parsed.HasErrors());
369 QVERIFY(parsed.diagnostics.empty());
370 runtime = DbcDecodeBuilder().Build(parsed.database);
371 tree = DbcTreeBuilder().Build(parsed.database);
372 QVERIFY(tree != nullptr);
373 QVERIFY(runtime.GetFrames().empty());
374 CheckUnknown(runtime, false);
375 CheckUnknown(runtime, true);
376 CheckTree(*tree, DbcDatabase());
377 QVERIFY(runtime.FindSignal(current.signals[0].key) == nullptr);
378 CheckFrame(*current.definition, replacement);
379 CheckFrame(*saved.definition, ExpectedMetadata().frames[0]);
380 CheckTree(*savedTree, ExpectedMetadata());
381 QCOMPARE(saved.signals[1].physicalValue, 9.0);
382 QVERIFY(saved.signals[1].GetValueDescription() != nullptr);
383 QCOMPARE(*saved.signals[1].GetValueDescription(), std::string("Standard four"));
384}
385
386int RunPipelineTests(int argc, char **argv) {
387 PipelineTest test;
388 return QTest::qExec(&test, argc, argv);
389}
390
391#include "dbc_pipeline_test.moc"
Converts parsed DBC data into runtime decode database.
DecodeDatabase Build(const DbcDatabase &source) const
Build runtime decode database.
Runtime CAN decoder using prebuilt decode database.
Definition dbc_decoder.h:86
DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
Decode one raw CAN frame.
Minimal DBC parser.
Definition dbc_parser.h:41
Builds a simple tree from parsed DBC database.
std::unique_ptr< TreeNode > Build(const DbcDatabase &database) const
Build tree representation of parsed DBC data.
Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
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
Tree node for later use in model/view or other hierarchy consumers.
Definition tree_node.h:37
const SignalInfo * GetSignal() const
Get signal payload if node is signal.
Definition tree_node.cpp:71
const TreeNode * GetChild(std::size_t index) const
Get child by index.
Definition tree_node.cpp:45
const TreeNode * GetParent() const
Definition tree_node.cpp:75
const std::string & GetName() const
Get display name.
Definition tree_node.cpp:63
std::size_t GetChildCount() const
Get child count.
Definition tree_node.cpp:41
std::size_t GetRow() const
Definition tree_node.cpp:79
NodeType GetType() const
Get node type.
Definition tree_node.cpp:59
const FrameInfo * GetFrame() const
Get frame payload if node is frame.
Definition tree_node.cpp:67
Runtime decode database builder.
CAN frame decoding API and result types.
DBC file parser and interpretation options.
Metadata tree builder.
ByteOrder
Signal byte order used for runtime decoding.
ValueType
Signal numeric type.
Parsed DBC content stored in a simple internal form.
std::vector< FrameInfo > frames
Parsed database and diagnostics; the database is empty on error.
std::vector< DbcDiagnostic > diagnostics
bool HasErrors() const
Return whether any diagnostic has error severity.
DbcDatabase database
Runtime-ready signal definition.
ValueType valueType
ByteOrder byteOrder
Fully decoded frame.
Definition dbc_decoder.h:73
std::shared_ptr< const DecodeFrame > definition
Definition dbc_decoder.h:74
FrameDecodeStatus status
Definition dbc_decoder.h:78
One decoded signal value.
Definition dbc_decoder.h:54
RawSignalValue rawValue
Definition dbc_decoder.h:57
std::shared_ptr< const DecodeSignal > definition
Definition dbc_decoder.h:55
SignalDecodeStatus status
Definition dbc_decoder.h:60
const std::string * GetValueDescription() const
Definition dbc_decoder.h:63
Describes one CAN frame from a DBC file.
Definition frame_info.h:25
bool isExtended
Definition frame_info.h:28
bool hasPgn
Definition frame_info.h:30
std::string transmitter
Definition frame_info.h:32
std::uint8_t dlc
Definition frame_info.h:31
std::string name
Definition frame_info.h:26
std::string comment
Definition frame_info.h:33
std::uint32_t pgn
Definition frame_info.h:29
std::uint32_t canId
Definition frame_info.h:27
Stable frame identifier: normalized CAN ID and frame type.
MultiplexRole role
std::uint64_t value
Raw CAN frame used for runtime or trace decoding.
Definition dbc_decoder.h:24
std::vector< std::uint8_t > data
Definition dbc_decoder.h:27
std::uint32_t canId
Definition dbc_decoder.h:25
bool isExtended
Definition dbc_decoder.h:26
Describes one signal inside a DBC frame.
Definition signal_info.h:25
std::uint32_t length
Definition signal_info.h:29
std::string unit
Definition signal_info.h:36
std::vector< std::string > receivers
Definition signal_info.h:37
std::string name
Definition signal_info.h:27
ValueDescriptions valueDescriptions
Definition signal_info.h:38
bool isSigned
Definition signal_info.h:31
Multiplexing multiplexing
Definition signal_info.h:26
double offset
Definition signal_info.h:33
std::string comment
Definition signal_info.h:39
std::uint32_t startBit
Definition signal_info.h:28
double minimum
Definition signal_info.h:34
double maximum
Definition signal_info.h:35
double factor
Definition signal_info.h:32
bool isLittleEndian
Definition signal_info.h:30