INSTINCT Code Coverage Report


Directory: src/
File: Nodes/Utility/Demo.cpp
Date: 2025-06-02 15:19:59
Exec Total Coverage
Lines: 185 423 43.7%
Functions: 19 26 73.1%
Branches: 233 918 25.4%

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