INSTINCT Code Coverage Report


Directory: src/
File: Nodes/Utility/Demo.cpp
Date: 2025-11-25 23:34:18
Exec Total Coverage
Lines: 185 423 43.7%
Functions: 19 26 73.1%
Branches: 230 912 25.2%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "Demo.hpp"
10 #include <cstddef>
11 #include <imgui.h>
12 #include <optional>
13
14 #include "util/Logger.hpp"
15
16 #include "internal/FlowManager.hpp"
17
18 #include "internal/gui/widgets/HelpMarker.hpp"
19 #include "internal/gui/widgets/Matrix.hpp"
20 #include "internal/gui/widgets/imgui_ex.hpp"
21
22 #include "NodeData/IMU/ImuObs.hpp"
23
24 #include <chrono>
25 #include <thread>
26 #include <random>
27
28 namespace NAV
29 {
30 namespace
31 {
32 InsTime getCurrentInsTime()
33 {
34 std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
35 auto* t = std::localtime(&now); // NOLINT(concurrency-mt-unsafe)
36
37 return { static_cast<uint16_t>(t->tm_year + 1900),
38 static_cast<uint16_t>(t->tm_mon),
39 static_cast<uint16_t>(t->tm_mday),
40 static_cast<uint16_t>(t->tm_hour),
41 static_cast<uint16_t>(t->tm_min),
42 static_cast<long double>(t->tm_sec) };
43 }
44 } // namespace
45
46 /// @brief Write info to a json object
47 /// @param[out] j Json output
48 /// @param[in] data Object to read info from
49 static void to_json(json& j, const Demo::DemoData& data) // NOLINT(misc-use-anonymous-namespace)
50 {
51 j = json{
52 { "boolean", data.boolean },
53 { "integer", data.integer },
54 };
55 }
56 /// @brief Read info from a json object
57 /// @param[in] j Json variable to read info from
58 /// @param[out] data Output object
59 6 static void from_json(const json& j, Demo::DemoData& data) // NOLINT(misc-use-anonymous-namespace)
60 {
61
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("boolean"))
62 {
63 6 j.at("boolean").get_to(data.boolean);
64 }
65
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("integer"))
66 {
67 6 j.at("integer").get_to(data.integer);
68 }
69 6 }
70
71 } // namespace NAV
72
73 120 NAV::Demo::Demo()
74
5/10
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 120 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 120 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 120 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 120 times.
✗ Branch 17 not taken.
360 : Node(typeStatic())
75 {
76 LOG_TRACE("{}: called", name);
77
78 120 _onlyRealTime = false; // Set this to true if you have a sensor, network stream, ...
79 120 _hasConfig = true;
80 120 _lockConfigDuringRun = false;
81 120 _guiConfigDefaultWindowSize = { 630, 410 };
82
83 // Pins are usually created by calling the following functions in the constructor
84
4/8
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 120 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 120 times.
✓ Branch 9 taken 120 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
360 CreateInputPin("Flow", Pin::Type::Flow, { NAV::NodeData::type() }, &Demo::receiveData);
85
4/8
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 120 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 120 times.
✓ Branch 10 taken 120 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
480 CreateOutputPin("Sensor\nData", Pin::Type::Flow, { NAV::ImuObs::type() });
86
87 // To create or delete pins depending on GUI options we use a function as it needs to be called from multiple places
88
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 updatePins();
89 360 }
90
91 252 NAV::Demo::~Demo()
92 {
93 LOG_TRACE("{}: called", nameId());
94 252 }
95
96 361 std::string NAV::Demo::typeStatic()
97 {
98
1/2
✓ Branch 1 taken 361 times.
✗ Branch 2 not taken.
722 return "Demo";
99 }
100
101 1 std::string NAV::Demo::type() const
102 {
103 1 return typeStatic();
104 }
105
106 114 std::string NAV::Demo::category()
107 {
108
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
228 return "Utility";
109 }
110
111 void NAV::Demo::guiConfig()
112 {
113 if (ImGui::BeginTable("##DemoValues", 3, ImGuiTableFlags_Borders))
114 {
115 ImGui::TableSetupColumn("Enable");
116 ImGui::TableSetupColumn("Input");
117 ImGui::TableSetupColumn("Output");
118 ImGui::TableHeadersRow();
119
120 /* ----------------------------------------------- Delegate ----------------------------------------------- */
121 ImGui::TableNextRow();
122 ImGui::TableSetColumnIndex(0);
123 if (ImGui::Checkbox(fmt::format("Delegate##enable {}", size_t(id)).c_str(), &_enableDelegate))
124 {
125 updatePins();
126 flow::ApplyChanges();
127 }
128 if (_enableDelegate)
129 {
130 ImGui::TableSetColumnIndex(1);
131 {
132 // The returned type automatically blocks editing on the other side of the link. Like a scoped_lock for mutexes
133 auto connectedNode = getInputValue<Demo>(getPinIdx(DemoPins::Delegate).value());
134 ImGui::Text("Delegate: %s", connectedNode ? connectedNode->v->nameId().c_str() : "N/A");
135 }
136 }
137 /* ------------------------------------------------ Flow ------------------------------------------------ */
138 ImGui::TableNextRow();
139 ImGui::TableSetColumnIndex(0);
140 if (ImGui::Checkbox(fmt::format("Flow##enable {}", size_t(id)).c_str(), &_enableFlow))
141 {
142 updatePins();
143 flow::ApplyChanges();
144 }
145 if (_enableFlow)
146 {
147 ImGui::TableSetColumnIndex(1);
148 ImGui::Text("Flow Data Count: %d", _receivedDataCnt);
149 ImGui::TableSetColumnIndex(2);
150 if (ImGui::Checkbox(fmt::format("Simulate File Reader##{}", size_t(id)).c_str(), &_fileReaderInsteadSensor))
151 {
152 if (_fileReaderInsteadSensor)
153 {
154 if (_timer.is_running()) { _timer.stop(); }
155 }
156 else
157 {
158 if (isInitialized() && !_timer.is_running())
159 {
160 int outputInterval = static_cast<int>(1.0 / static_cast<double>(_outputFrequency) * 1000.0);
161 _timer.start(outputInterval, readSensorDataThread, this);
162 }
163 }
164 updateOutputFlowPin();
165 flow::ApplyChanges();
166 }
167 if (_fileReaderInsteadSensor)
168 {
169 ImGui::SetNextItemWidth(100.0F);
170 if (ImGui::InputInt(fmt::format("FileReader Obs Count##{}", size_t(id)).c_str(), &_nPollData))
171 {
172 flow::ApplyChanges();
173 }
174 }
175 else
176 {
177 if (ImGui::SliderInt(fmt::format("Frequency##{}", size_t(id)).c_str(), &_outputFrequency, 1, 10))
178 {
179 int outputInterval = static_cast<int>(1.0 / static_cast<double>(_outputFrequency) * 1000.0);
180 _timer.setInterval(outputInterval);
181 flow::ApplyChanges();
182 }
183 }
184 }
185 /* ------------------------------------------------- Bool ------------------------------------------------- */
186 ImGui::TableNextRow();
187 ImGui::TableSetColumnIndex(0);
188 if (ImGui::Checkbox(fmt::format("Bool##enable {}", size_t(id)).c_str(), &_enableBool))
189 {
190 updatePins();
191 flow::ApplyChanges();
192 }
193 if (_enableBool)
194 {
195 ImGui::TableSetColumnIndex(1);
196 {
197 auto connectedBool = getInputValue<bool>(getPinIdx(DemoPins::Bool).value());
198 ImGui::Text("Bool: %s", connectedBool ? (connectedBool->v ? "true" : "false") : "N/A");
199 }
200
201 ImGui::TableSetColumnIndex(2);
202 {
203 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Bool).value());
204 if (ImGui::Checkbox(fmt::format("Bool##{}", size_t(id)).c_str(), &_valueBool))
205 {
206 flow::ApplyChanges();
207 }
208 }
209 }
210 /* -------------------------------------------------- Int ------------------------------------------------- */
211 ImGui::TableNextRow();
212 ImGui::TableSetColumnIndex(0);
213 if (ImGui::Checkbox(fmt::format("Int##enable {}", size_t(id)).c_str(), &_enableInt))
214 {
215 updatePins();
216 flow::ApplyChanges();
217 }
218 if (_enableInt)
219 {
220 ImGui::TableSetColumnIndex(1);
221 if (auto connectedInt = getInputValue<int>(getPinIdx(DemoPins::Int).value()))
222 {
223 ImGui::Text("Int: %d", *connectedInt->v);
224 }
225 else
226 {
227 ImGui::TextUnformatted("Int: N/A");
228 }
229
230 ImGui::TableSetColumnIndex(2);
231 {
232 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Int).value());
233 if (ImGui::InputInt(fmt::format("Int##{}", size_t(id)).c_str(), &_valueInt)) // Returns true if a change was made
234 {
235 // Limit the values to [-2,5]
236 _valueInt = std::max(_valueInt, -2);
237 _valueInt = std::min(_valueInt, 5);
238
239 flow::ApplyChanges();
240 }
241 }
242 }
243 /* ------------------------------------------------- Float ------------------------------------------------ */
244 ImGui::TableNextRow();
245 ImGui::TableSetColumnIndex(0);
246 if (ImGui::Checkbox(fmt::format("Float##enable {}", size_t(id)).c_str(), &_enableFloat))
247 {
248 updatePins();
249 flow::ApplyChanges();
250 }
251 if (_enableFloat)
252 {
253 ImGui::TableSetColumnIndex(1);
254 if (auto connectedFloat = getInputValue<float>(getPinIdx(DemoPins::Float).value()))
255 {
256 ImGui::Text("Float: %.3f", *connectedFloat->v);
257 }
258 else
259 {
260 ImGui::TextUnformatted("Float: N/A");
261 }
262
263 ImGui::TableSetColumnIndex(2);
264 {
265 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Float).value());
266 if (ImGui::DragFloat(fmt::format("Float##{}", size_t(id)).c_str(), &_valueFloat))
267 {
268 flow::ApplyChanges();
269 }
270 }
271 }
272 /* ------------------------------------------------ Double ------------------------------------------------ */
273 ImGui::TableNextRow();
274 ImGui::TableSetColumnIndex(0);
275 if (ImGui::Checkbox(fmt::format("Double##enable {}", size_t(id)).c_str(), &_enableDouble))
276 {
277 updatePins();
278 flow::ApplyChanges();
279 }
280 if (_enableDouble)
281 {
282 ImGui::TableSetColumnIndex(1);
283 if (auto connectedDouble = getInputValue<double>(getPinIdx(DemoPins::Double).value()))
284 {
285 ImGui::Text("Double : %.3f", *connectedDouble->v);
286 }
287 else
288 {
289 ImGui::TextUnformatted("Double: N/A");
290 }
291
292 ImGui::TableSetColumnIndex(2);
293 {
294 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Double).value());
295 if (ImGui::DragDouble(fmt::format("Double##{}", size_t(id)).c_str(), &_valueDouble))
296 {
297 flow::ApplyChanges();
298 }
299 }
300 }
301 /* ------------------------------------------------ String ------------------------------------------------ */
302 ImGui::TableNextRow();
303 ImGui::TableSetColumnIndex(0);
304 if (ImGui::Checkbox(fmt::format("String##enable {}", size_t(id)).c_str(), &_enableString))
305 {
306 updatePins();
307 flow::ApplyChanges();
308 }
309 if (_enableString)
310 {
311 ImGui::TableSetColumnIndex(1);
312 if (auto connectedString = getInputValue<std::string>(getPinIdx(DemoPins::String).value()))
313 {
314 ImGui::Text("String: %s", connectedString->v->c_str());
315 }
316 else
317 {
318 ImGui::TextUnformatted("String: N/A");
319 }
320 ImGui::Text("The String was updated %lu time%s", _stringUpdateCounter, _stringUpdateCounter > 1 || _stringUpdateCounter == 0 ? "s" : "");
321
322 ImGui::TableSetColumnIndex(2);
323 {
324 // Before accessing and changing the value. A lock has to be requested to ensure it is not changed before all linked nodes received the value.
325 auto guard = requestOutputValueLock(getPinIdx(DemoPins::String).value());
326 if (ImGui::InputText(fmt::format("String##{}", size_t(id)).c_str(), &_valueString))
327 {
328 flow::ApplyChanges();
329 const auto& outputPin = outputPins[getPinIdx(DemoPins::String).value()];
330 if (outputPin.isPinLinked())
331 {
332 if (!isInitialized()) { LOG_WARN("{}: Notifying connected nodes requires this node to be initialized.", nameId()); }
333 else if (!callbacksEnabled) { LOG_WARN("{}: Notifying connected nodes requires enabled callbacks on this node. Do this by running the flow.", nameId()); }
334 else if (std::ranges::none_of(outputPin.links, [](const OutputPin::OutgoingLink& link) { return link.connectedNode->isInitialized(); }))
335 {
336 LOG_WARN("{}: Notifying connected nodes requires at least one connected node to be initialized.", nameId());
337 }
338 }
339 notifyOutputValueChanged(getPinIdx(DemoPins::String).value(), getCurrentInsTime(), std::move(guard));
340 }
341 }
342 ImGui::SameLine();
343 gui::widgets::HelpMarker("The string notifies about changes.\nInitialize both nodes for this to work.");
344 }
345 /* ------------------------------------------------ Object ------------------------------------------------ */
346 ImGui::TableNextRow();
347 ImGui::TableSetColumnIndex(0);
348 if (ImGui::Checkbox(fmt::format("Object##enable {}", size_t(id)).c_str(), &_enableObject))
349 {
350 updatePins();
351 flow::ApplyChanges();
352 }
353 if (_enableObject)
354 {
355 ImGui::TableSetColumnIndex(1);
356 if (auto connectedObject = getInputValue<DemoData>(getPinIdx(DemoPins::Object).value()))
357 {
358 ImGui::Text("Object: [%d, %d, %d], %s", connectedObject->v->integer.at(0), connectedObject->v->integer.at(1), connectedObject->v->integer.at(2),
359 connectedObject->v->boolean ? "true" : "false");
360 }
361 else
362 {
363 ImGui::TextUnformatted("Object: N/A");
364 }
365
366 ImGui::TableSetColumnIndex(2);
367 {
368 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Object).value());
369 if (ImGui::InputInt3(fmt::format("##object.integer {}", size_t(id)).c_str(), _valueObject.integer.data()))
370 {
371 flow::ApplyChanges();
372 }
373 ImGui::SameLine();
374 if (ImGui::Checkbox(fmt::format("Object##{}", size_t(id)).c_str(), &_valueObject.boolean))
375 {
376 flow::ApplyChanges();
377 }
378 }
379 }
380 /* ------------------------------------------------ Matrix ------------------------------------------------ */
381 ImGui::TableNextRow();
382 ImGui::TableSetColumnIndex(0);
383 if (ImGui::Checkbox(fmt::format("Matrix##enable {}", size_t(id)).c_str(), &_enableMatrix))
384 {
385 updatePins();
386 flow::ApplyChanges();
387 }
388 if (_enableMatrix)
389 {
390 ImGui::TableSetColumnIndex(1);
391 if (auto connectedMatrix = getInputValue<Eigen::MatrixXd>(getPinIdx(DemoPins::Matrix).value()))
392 {
393 gui::widgets::MatrixView("Current Matrix", connectedMatrix->v, GuiMatrixViewFlags_Header, ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_SizingFixedFit, "%.1f");
394 }
395 else
396 {
397 ImGui::TextUnformatted("Matrix: N/A");
398 }
399
400 ImGui::TableSetColumnIndex(2);
401 {
402 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Matrix).value());
403 if (gui::widgets::InputMatrix(fmt::format("Init Matrix##{}", size_t(id)).c_str(), &_valueMatrix, GuiMatrixViewFlags_Header, ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_SizingFixedFit, 30.0F, 0.0, 0.0, "%.1f"))
404 {
405 flow::ApplyChanges();
406 }
407 }
408 }
409
410 ImGui::EndTable();
411 }
412 }
413
414 [[nodiscard]] json NAV::Demo::save() const
415 {
416 LOG_TRACE("{}: called", nameId());
417
418 json j;
419
420 return {
421 { "outputFrequency", _outputFrequency },
422 { "nPollData", _nPollData },
423 { "enableDelegate", _enableDelegate },
424 { "enableFlow", _enableFlow },
425 { "enableBool", _enableBool },
426 { "enableInt", _enableInt },
427 { "enableFloat", _enableFloat },
428 { "enableDouble", _enableDouble },
429 { "enableString", _enableString },
430 { "enableObject", _enableObject },
431 { "enableMatrix", _enableMatrix },
432 { "valueBool", _valueBool },
433 { "valueInt", _valueInt },
434 { "valueFloat", _valueFloat },
435 { "valueDouble", _valueDouble },
436 { "valueString", _valueString },
437 { "valueObject", _valueObject },
438 { "valueMatrix", _valueMatrix },
439 { "fileReaderInsteadSensor", _fileReaderInsteadSensor },
440 };
441 }
442
443 6 void NAV::Demo::restore(json const& j)
444 {
445 LOG_TRACE("{}: called", nameId());
446
447
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("outputFrequency")) { j.at("outputFrequency").get_to(_outputFrequency); }
448
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("nPollData")) { j.at("nPollData").get_to(_nPollData); }
449
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("enableDelegate")) { j.at("enableDelegate").get_to(_enableDelegate); }
450
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("enableFlow")) { j.at("enableFlow").get_to(_enableFlow); }
451
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("enableBool")) { j.at("enableBool").get_to(_enableBool); }
452
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("enableInt")) { j.at("enableInt").get_to(_enableInt); }
453
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("enableFloat")) { j.at("enableFloat").get_to(_enableFloat); }
454
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("enableDouble")) { j.at("enableDouble").get_to(_enableDouble); }
455
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("enableString")) { j.at("enableString").get_to(_enableString); }
456
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("enableObject")) { j.at("enableObject").get_to(_enableObject); }
457
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("enableMatrix")) { j.at("enableMatrix").get_to(_enableMatrix); }
458
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("valueBool")) { j.at("valueBool").get_to(_valueBool); }
459
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("valueInt")) { j.at("valueInt").get_to(_valueInt); }
460
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("valueFloat")) { j.at("valueFloat").get_to(_valueFloat); }
461
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("valueDouble")) { j.at("valueDouble").get_to(_valueDouble); }
462
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("valueString")) { j.at("valueString").get_to(_valueString); }
463
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("valueObject")) { j.at("valueObject").get_to(_valueObject); }
464
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("valueMatrix")) { j.at("valueMatrix").get_to(_valueMatrix); }
465
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (j.contains("fileReaderInsteadSensor"))
466 {
467 6 j.at("fileReaderInsteadSensor").get_to(_fileReaderInsteadSensor);
468 6 updateOutputFlowPin();
469 }
470 6 updatePins();
471 6 }
472
473 6 bool NAV::Demo::initialize()
474 {
475 LOG_TRACE("{}: called", nameId());
476
477 // To Show the Initialization in the GUI
478
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
6 std::this_thread::sleep_for(std::chrono::milliseconds(2000));
479
480 5 _receivedDataCnt = 0;
481
482 5 _stringUpdateCounter = 0;
483
484
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
5 if (_enableFlow && !_fileReaderInsteadSensor)
485 {
486 // The Timer is used to simulate a sensor reader
487 3 int outputInterval = static_cast<int>(1.0 / static_cast<double>(_outputFrequency) * 1000.0);
488
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 _timer.start(outputInterval, readSensorDataThread, this);
489 }
490
491 6 return true;
492 }
493
494 6 void NAV::Demo::deinitialize()
495 {
496 LOG_TRACE("{}: called", nameId());
497
498
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
6 if (_timer.is_running())
499 {
500 4 _timer.stop();
501 }
502
503 // To Show the Deinitialization in the GUI
504
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
505 6 }
506
507 126 void NAV::Demo::updatePins()
508 {
509 126 size_t pinIdx = 0;
510
511 1008 auto updatePin = [&](bool pinExists, bool enabled,
512 const char* pinName, Pin::Type pinType, const std::vector<std::string>& dataIdentifier = {}, // BUG: Bug in clang-format, so we need to disable formatting
513 OutputPin::PinData data = static_cast<void*>(nullptr), // clang-format off
514 void(NAV::Demo::*notifyFunc)(const InsTime&, size_t) = nullptr) { // clang-format on
515
3/4
✓ Branch 0 taken 1008 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 991 times.
1008 if (!pinExists && enabled)
516 {
517 17 CreateInputPin(pinName, pinType, dataIdentifier, notifyFunc, static_cast<int>(pinIdx));
518 17 CreateOutputPin(pinName, pinType, dataIdentifier, data, static_cast<int>(pinIdx));
519 }
520
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 991 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
991 else if (pinExists && !enabled)
521 {
522 DeleteInputPin(pinIdx);
523 DeleteOutputPin(pinIdx);
524 }
525
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 991 times.
1008 if (enabled) { pinIdx++; }
526 1134 };
527
528
6/18
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 126 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 21 taken 126 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 126 times.
✓ Branch 25 taken 126 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
378 updatePin(getPinIdx(DemoPins::Delegate) && inputPins.at(*getPinIdx(DemoPins::Delegate)).type == Pin::Type::Delegate, _enableDelegate,
529 126 "Demo Node", Pin::Type::Delegate, { typeStatic() }, this);
530 // CreateInputPin("Demo Node", Pin::Type::Delegate, { typeStatic() });
531 // CreateOutputPin("", Pin::Type::Delegate, { typeStatic() }, this, 0);
532
533 {
534
5/10
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 126 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 126 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 126 times.
✗ Branch 15 not taken.
126 bool pinExists = getPinIdx(DemoPins::Flow) && inputPins.at(*getPinIdx(DemoPins::Flow)).type == Pin::Type::Flow;
535
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
126 if (!pinExists && _enableFlow)
536 {
537 CreateInputPin("Flow", Pin::Type::Flow, { NAV::NodeData::type() }, &Demo::receiveData);
538 CreateOutputPin("Sensor\nData", Pin::Type::Flow, { NAV::ImuObs::type() });
539 }
540
3/4
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 125 times.
126 else if (pinExists && !_enableFlow)
541 {
542
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 DeleteInputPin(pinIdx);
543
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 DeleteOutputPin(pinIdx);
544 }
545
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 1 times.
126 if (_enableFlow) { pinIdx++; }
546 }
547
548
4/14
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 126 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 21 taken 126 times.
✗ Branch 22 not taken.
252 updatePin(getPinIdx(DemoPins::Bool) && inputPins.at(*getPinIdx(DemoPins::Bool)).type == Pin::Type::Bool, _enableBool,
549 126 "Bool", Pin::Type::Bool, { "" }, &_valueBool);
550 // CreateInputPin("Bool", Pin::Type::Bool);
551 // CreateOutputPin("Bool", Pin::Type::Bool, { "" }, &_valueBool);
552
553
4/14
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 126 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 21 taken 126 times.
✗ Branch 22 not taken.
252 updatePin(getPinIdx(DemoPins::Int) && inputPins.at(*getPinIdx(DemoPins::Int)).type == Pin::Type::Int, _enableInt,
554 126 "Int", Pin::Type::Int, { "" }, &_valueInt);
555 // CreateInputPin("Int", Pin::Type::Int);
556 // CreateOutputPin("Int", Pin::Type::Int, { "" }, &_valueInt);
557
558
4/14
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 126 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 21 taken 126 times.
✗ Branch 22 not taken.
252 updatePin(getPinIdx(DemoPins::Float) && inputPins.at(*getPinIdx(DemoPins::Float)).type == Pin::Type::Float, _enableFloat,
559 126 "Float", Pin::Type::Float, { "Float" }, &_valueFloat);
560 // CreateInputPin("Float", Pin::Type::Float);
561 // CreateOutputPin("Float", Pin::Type::Float, { "" }, &_valueFloat);
562
563
4/14
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 126 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 21 taken 126 times.
✗ Branch 22 not taken.
252 updatePin(getPinIdx(DemoPins::Double) && inputPins.at(*getPinIdx(DemoPins::Double)).type == Pin::Type::Float, _enableDouble,
564 126 "Double", Pin::Type::Float, { "Double" }, &_valueDouble);
565 // CreateInputPin("Double", Pin::Type::Float);
566 // CreateOutputPin("Double", Pin::Type::Float, { "" }, &_valueDouble);
567
568
4/14
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 126 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 21 taken 126 times.
✗ Branch 22 not taken.
252 updatePin(getPinIdx(DemoPins::String) && inputPins.at(*getPinIdx(DemoPins::String)).type == Pin::Type::String, _enableString,
569 126 "String", Pin::Type::String, { "" }, &_valueString, &Demo::stringUpdatedNotifyFunction);
570 // CreateInputPin("String", Pin::Type::String, {}, &Demo::stringUpdatedNotifyFunction);
571 // CreateOutputPin("String", Pin::Type::String, { "" }, &_valueString);
572
573
4/14
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 126 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 21 taken 126 times.
✗ Branch 22 not taken.
252 updatePin(getPinIdx(DemoPins::Object) && inputPins.at(*getPinIdx(DemoPins::Object)).type == Pin::Type::Object, _enableObject,
574 126 "Object", Pin::Type::Object, { "Demo::DemoData" }, &_valueObject);
575 // CreateInputPin("Object", Pin::Type::Object, { "Demo::DemoData" });
576 // CreateOutputPin("Object", Pin::Type::Object, { "Demo::DemoData" }, &_valueObject);
577
578
4/14
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 126 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 21 taken 126 times.
✗ Branch 22 not taken.
252 updatePin(getPinIdx(DemoPins::Matrix) && inputPins.at(*getPinIdx(DemoPins::Matrix)).type == Pin::Type::Matrix, _enableMatrix,
579 126 "Matrix", Pin::Type::Matrix, { "Eigen::MatrixXd" }, &_valueMatrix);
580 // CreateInputPin("Matrix", Pin::Type::Matrix, { "Eigen::MatrixXd" });
581 // CreateOutputPin("Matrix", Pin::Type::Matrix, { "Eigen::MatrixXd" }, &_valueMatrix);
582 252 }
583
584 1414 std::optional<size_t> NAV::Demo::getPinIdx(DemoPins pinType) const
585 {
586
2/2
✓ Branch 1 taken 1559 times.
✓ Branch 2 taken 999 times.
2560 for (size_t i = 0; i < inputPins.size(); i++)
587 {
588
9/10
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 500 times.
✓ Branch 2 taken 127 times.
✓ Branch 3 taken 129 times.
✓ Branch 4 taken 131 times.
✓ Branch 5 taken 133 times.
✓ Branch 6 taken 135 times.
✓ Branch 7 taken 138 times.
✓ Branch 8 taken 140 times.
✗ Branch 9 not taken.
1559 switch (pinType)
589 {
590 126 case DemoPins::Delegate:
591
2/4
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 126 times.
126 if (inputPins.at(i).type == Pin::Type::Delegate) { return i; }
592 126 break;
593 500 case DemoPins::Flow:
594
3/4
✓ Branch 1 taken 496 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 410 times.
✓ Branch 5 taken 87 times.
500 if (inputPins.at(i).type == Pin::Type::Flow) { return i; }
595 87 break;
596 127 case DemoPins::Bool:
597
2/4
✓ Branch 1 taken 127 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 127 times.
127 if (inputPins.at(i).type == Pin::Type::Bool) { return i; }
598 127 break;
599 129 case DemoPins::Int:
600
2/4
✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 129 times.
129 if (inputPins.at(i).type == Pin::Type::Int) { return i; }
601 129 break;
602 131 case DemoPins::Float:
603
3/12
✓ Branch 1 taken 131 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 131 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 131 times.
131 if (inputPins.at(i).type == Pin::Type::Float && inputPins.at(i).dataIdentifier.front() == "Float") { return i; }
604 131 break;
605 133 case DemoPins::Double:
606
7/12
✓ Branch 1 taken 133 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 131 times.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 133 times.
133 if (inputPins.at(i).type == Pin::Type::Float && inputPins.at(i).dataIdentifier.front() == "Double") { return i; }
607 133 break;
608 135 case DemoPins::String:
609
2/4
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 135 times.
135 if (inputPins.at(i).type == Pin::Type::String) { return i; }
610 135 break;
611 138 case DemoPins::Object:
612
2/4
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 138 times.
138 if (inputPins.at(i).type == Pin::Type::Object) { return i; }
613 138 break;
614 140 case DemoPins::Matrix:
615
2/4
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 140 times.
140 if (inputPins.at(i).type == Pin::Type::Matrix) { return i; }
616 140 break;
617 }
618 }
619
620 999 return std::nullopt;
621 }
622
623 12 bool NAV::Demo::resetNode()
624 {
625 LOG_TRACE("{}: called", nameId());
626 // Here you could reset a FileReader
627 12 _iPollData = 0;
628 12 _receivedDataCnt = 0;
629
630 12 return true;
631 }
632
633 6 void NAV::Demo::updateOutputFlowPin()
634 {
635
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 size_t flowPinIdx = getPinIdx(DemoPins::Flow).value();
636 6 std::vector<ax::NodeEditor::PinId> connectedPins;
637
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
6 for (const auto& link : outputPins.at(flowPinIdx).links)
638 {
639 connectedPins.push_back(link.connectedPinId);
640 }
641
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 DeleteOutputPin(flowPinIdx);
642
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (_fileReaderInsteadSensor)
643 {
644
4/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
3 CreateOutputPin("FileReader\n Data", Pin::Type::Flow, { NAV::NodeData::type() }, &Demo::pollData, static_cast<int>(flowPinIdx));
645 }
646 else
647 {
648
4/8
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 5 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
20 CreateOutputPin("Sensor\nData", Pin::Type::Flow, { NAV::ImuObs::type() }, static_cast<void*>(nullptr), static_cast<int>(flowPinIdx));
649 }
650
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
6 for (const auto& pinId : connectedPins)
651 {
652 if (auto* targetPin = flow::FindInputPin(pinId))
653 {
654 if (outputPins.at(flowPinIdx).canCreateLink(*targetPin))
655 {
656 outputPins.at(flowPinIdx).createLink(*targetPin);
657 }
658 }
659 }
660 12 }
661
662 24 bool NAV::Demo::onCreateLink([[maybe_unused]] OutputPin& startPin, [[maybe_unused]] InputPin& endPin)
663 {
664 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
665
666
10/14
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 23 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 23 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 9 times.
✓ Branch 15 taken 14 times.
✓ Branch 16 taken 9 times.
✓ Branch 17 taken 15 times.
24 if (_enableFlow && outputPins.at(getPinIdx(DemoPins::Flow).value()).isPinLinked())
667 {
668 9 _onlyRealTime = !_fileReaderInsteadSensor;
669 }
670
671 24 return true;
672 }
673
674 24 void NAV::Demo::afterDeleteLink([[maybe_unused]] OutputPin& startPin, [[maybe_unused]] InputPin& endPin)
675 {
676 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
677
678
10/14
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 23 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 23 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 13 times.
✓ Branch 15 taken 10 times.
✓ Branch 16 taken 13 times.
✓ Branch 17 taken 11 times.
24 if (_enableFlow && !outputPins.at(getPinIdx(DemoPins::Flow).value()).isPinLinked())
679 {
680 13 _onlyRealTime = false;
681 }
682 24 }
683
684 30 void NAV::Demo::receiveData(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */)
685 {
686
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
30 std::shared_ptr<const NAV::NodeData> obs = queue.extract_front(); // Either 'extract_front()' or 'pop_front()' needs to be called
687 29 _receivedDataCnt++;
688
689
4/8
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 30 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 30 times.
✗ Branch 14 not taken.
29 LOG_DEBUG("{}: received {} data at [{} GPST]", nameId(), _receivedDataCnt, obs->insTime.toYMDHMS(GPST));
690 30 }
691
692 43 void NAV::Demo::readSensorDataThread(void* userData)
693 {
694 43 auto* node = static_cast<Demo*>(userData);
695
696
5/8
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 38 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 38 times.
77 if (!node->_enableFlow || !node->getPinIdx(DemoPins::Flow).has_value()) { return; }
697
698
10/14
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 33 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 39 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✓ Branch 13 taken 26 times.
✓ Branch 14 taken 8 times.
✓ Branch 15 taken 5 times.
✓ Branch 16 taken 34 times.
✓ Branch 17 taken 5 times.
38 if (!node->outputPins.at(node->getPinIdx(DemoPins::Flow).value()).isPinLinked() || !node->callbacksEnabled)
699 {
700 34 return;
701 }
702
703
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
5 if (node->getMode() == Mode::POST_PROCESSING)
704 {
705 LOG_WARN("{}: Flow contains nodes which can only do post-processing. Sensor output is suppressed.");
706
707 return;
708 }
709
710
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 auto imuPos = ImuPos();
711
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 auto obs = std::make_shared<ImuObs>(imuPos);
712
713 5 std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
714 5 auto* t = std::gmtime(&now); // NOLINT(concurrency-mt-unsafe)
715
716 5 obs->insTime = InsTime(static_cast<uint16_t>(t->tm_year + 1900), static_cast<uint16_t>(t->tm_mon) + 1, static_cast<uint16_t>(t->tm_mday),
717
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 static_cast<uint16_t>(t->tm_hour), static_cast<uint16_t>(t->tm_min), static_cast<long double>(t->tm_sec), GPST);
718
719
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 std::random_device rd;
720
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
5 std::default_random_engine generator(rd());
721
722
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 std::uniform_real_distribution<double> distribution(-9.0, 9.0);
723
4/8
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
5 obs->p_acceleration = Eigen::Vector3d(distribution(generator), distribution(generator), distribution(generator));
724
725
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 distribution = std::uniform_real_distribution<double>(-3.0, 3.0);
726
4/8
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
5 obs->p_angularRate = Eigen::Vector3d(distribution(generator), distribution(generator), distribution(generator));
727
728
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 distribution = std::uniform_real_distribution<double>(-1.0, 1.0);
729
4/8
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
5 obs->p_magneticField = Eigen::Vector3d(distribution(generator), distribution(generator), distribution(generator));
730
731
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 distribution = std::uniform_real_distribution<double>(15.0, 25.0);
732
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 obs->temperature = distribution(generator);
733
734
4/8
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 5 times.
✗ Branch 14 not taken.
5 LOG_INFO("{}: Sending Sensor data with time [{} GPST]", node->nameId(), obs->insTime.toYMDHMS(GPST));
735
736
3/6
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
5 node->invokeCallbacks(node->getPinIdx(DemoPins::Flow).value(), obs);
737 5 }
738
739 std::shared_ptr<const NAV::NodeData> NAV::Demo::peekPollData(bool peek)
740 {
741 // This function is only an example of how to implement peek/poll logic. It is not used in this node.
742 if (_iPollData >= _nPollData)
743 {
744 return nullptr;
745 }
746
747 if (peek) // Early return with time to let the Node sort the observations
748 {
749 auto obs = std::make_shared<NodeData>(); // Construct the real observation (here in example also from type NodeData)
750 obs->insTime = InsTime(2000, 1, 1, 0, 0, _iPollData);
751 return obs;
752 }
753
754 auto obs = std::make_shared<NodeData>(); // Construct the real observation (here in example also from type NodeData)
755 obs->insTime = InsTime(2000, 1, 1, 0, 0, _iPollData);
756
757 _iPollData++;
758 // Calls all the callbacks
759 invokeCallbacks(getPinIdx(DemoPins::Flow).value(), obs);
760
761 return obs;
762 }
763
764 21 std::shared_ptr<const NAV::NodeData> NAV::Demo::pollData()
765 {
766
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 20 times.
21 if (_iPollData >= _nPollData)
767 {
768 1 return nullptr; // Tells the node that the last message was read
769 }
770
771
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 auto obs = std::make_shared<NodeData>(); // Construct the real observation (here in example also from type NodeData)
772
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 obs->insTime = InsTime(2000, 1, 1, 0, 0, _iPollData);
773
774 20 _iPollData++;
775
776
3/6
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 20 times.
✗ Branch 9 not taken.
20 invokeCallbacks(getPinIdx(DemoPins::Flow).value(), obs); // Calls all the callbacks
777 20 return obs;
778 20 }
779
780 void NAV::Demo::stringUpdatedNotifyFunction([[maybe_unused]] const InsTime& insTime, size_t pinIdx)
781 {
782 _stringUpdateCounter++;
783
784 if (auto value = getInputValue<std::string>(pinIdx))
785 {
786 LOG_DEBUG("String value updated to '{}' at time {}", *value->v, insTime);
787 }
788 }
789