INSTINCT Code Coverage Report


Directory: src/
File: Nodes/Converter/GNSS/UartPacketConverter.cpp
Date: 2025-11-25 23:34:18
Exec Total Coverage
Lines: 13 112 11.6%
Functions: 4 10 40.0%
Branches: 12 223 5.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 "UartPacketConverter.hpp"
10
11 #include <memory>
12
13 #include "util/Logger.hpp"
14 #include "util/Time/TimeBase.hpp"
15
16 #include "internal/FlowManager.hpp"
17
18 #include "util/Vendor/Ublox/UbloxUtilities.hpp"
19 #include "util/Vendor/Emlid/EmlidUtilities.hpp"
20 #include "util/Vendor/Espressif/EspressifUtilities.hpp"
21
22 #include "Nodes/DataProvider/IMU/Sensors/VectorNavSensor.hpp"
23
24 #include "NodeData/General/UartPacket.hpp"
25 #include "NodeData/GNSS/UbloxObs.hpp"
26 #include "NodeData/GNSS/EmlidObs.hpp"
27 #include "NodeData/WiFi/WiFiObs.hpp"
28
29 114 NAV::UartPacketConverter::UartPacketConverter()
30
2/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
114 : Node(typeStatic())
31 {
32 LOG_TRACE("{}: called", name);
33 114 _hasConfig = true;
34 114 _guiConfigDefaultWindowSize = { 340, 93 };
35
36
4/8
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 114 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 114 times.
✓ Branch 10 taken 114 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
456 CreateOutputPin("UbloxObs", Pin::Type::Flow, { NAV::UbloxObs::type() });
37
38
4/8
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 114 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 114 times.
✓ Branch 9 taken 114 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
342 CreateInputPin("UartPacket", Pin::Type::Flow, { NAV::UartPacket::type() }, &UartPacketConverter::receiveObs);
39 342 }
40
41 228 NAV::UartPacketConverter::~UartPacketConverter()
42 {
43 LOG_TRACE("{}: called", nameId());
44 228 }
45
46 228 std::string NAV::UartPacketConverter::typeStatic()
47 {
48
1/2
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
456 return "UartPacketConverter";
49 }
50
51 ✗ std::string NAV::UartPacketConverter::type() const
52 {
53 ✗ return typeStatic();
54 }
55
56 114 std::string NAV::UartPacketConverter::category()
57 {
58
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
228 return "Converter";
59 }
60
61 ✗ void NAV::UartPacketConverter::guiConfig()
62 {
63 ✗ if (auto outputType = static_cast<int>(_outputType);
64 ✗ ImGui::Combo(fmt::format("Output Type##{}", size_t(id)).c_str(), &outputType, "UbloxObs\0EmlidObs\0WiFiObs\0\0"))
65 {
66 ✗ _outputType = static_cast<decltype(_outputType)>(outputType);
67 ✗ std::string outputTypeString;
68 ✗ switch (_outputType)
69 {
70 ✗ case OutputType_UbloxObs:
71 ✗ outputTypeString = "UbloxObs";
72 ✗ break;
73 ✗ case OutputType_EmlidObs:
74 ✗ outputTypeString = "EmlidObs";
75 ✗ break;
76 ✗ default:
77 ✗ outputTypeString = "WiFiObs";
78 }
79
80 ✗ LOG_DEBUG("{}: Output Type changed to {}", nameId(), outputTypeString);
81
82 ✗ if (_outputType == OutputType_UbloxObs)
83 {
84 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::UbloxObs::type() };
85 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::UbloxObs::type();
86 }
87 ✗ else if (_outputType == OutputType_EmlidObs)
88 {
89 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::EmlidObs::type() };
90 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::EmlidObs::type();
91 }
92 ✗ else if (_outputType == OutputType_WiFiObs)
93 {
94 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::WiFiObs::type() };
95 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::WiFiObs::type();
96 }
97
98 ✗ for (auto& link : outputPins.front().links)
99 {
100 ✗ if (auto* connectedPin = link.getConnectedPin())
101 {
102 ✗ outputPins.front().recreateLink(*connectedPin);
103 }
104 }
105 ✗ flow::ApplyChanges();
106 ✗ }
107
108 ✗ if (_outputType == OutputType_WiFiObs)
109 {
110 ✗ if (ImGui::Checkbox(fmt::format("Show SyncIn Pin##{}", size_t(id)).c_str(), &_syncInPin))
111 {
112 ✗ LOG_DEBUG("{}: syncInPin changed to {}", nameId(), _syncInPin);
113 ✗ flow::ApplyChanges();
114 ✗ if (_syncInPin && (inputPins.size() <= 1))
115 {
116 ✗ CreateInputPin("SyncIn", Pin::Type::Object, { "TimeSync" });
117 }
118 ✗ else if (!_syncInPin)
119 {
120 ✗ DeleteInputPin(INPUT_PORT_INDEX_SYNC_IN);
121 }
122 }
123 // Remove the extra flow::ApplyChanges() statement here
124 }
125 ✗ else if (inputPins.size() > 1)
126 {
127 ✗ DeleteInputPin(INPUT_PORT_INDEX_SYNC_IN);
128 }
129 ✗ }
130
131 ✗ [[nodiscard]] json NAV::UartPacketConverter::save() const
132 {
133 LOG_TRACE("{}: called", nameId());
134
135 ✗ json j;
136
137 ✗ j["outputType"] = _outputType;
138 ✗ j["syncInPin"] = _syncInPin;
139
140 ✗ return j;
141 ✗ }
142
143 ✗ void NAV::UartPacketConverter::restore(json const& j)
144 {
145 LOG_TRACE("{}: called", nameId());
146
147 ✗ if (j.contains("outputType"))
148 {
149 ✗ j.at("outputType").get_to(_outputType);
150
151 ✗ if (!outputPins.empty())
152 {
153 ✗ if (_outputType == OutputType_UbloxObs)
154 {
155 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::UbloxObs::type() };
156 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::UbloxObs::type();
157 }
158 ✗ else if (_outputType == OutputType_EmlidObs)
159 {
160 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::EmlidObs::type() };
161 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::EmlidObs::type();
162 }
163 ✗ else if (_outputType == OutputType_WiFiObs)
164 {
165 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::WiFiObs::type() };
166 ✗ outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::WiFiObs::type();
167 }
168 }
169 }
170 ✗ if (j.contains("syncInPin") && _outputType == OutputType_WiFiObs)
171 {
172 ✗ j.at("syncInPin").get_to(_syncInPin);
173 ✗ if (_syncInPin && inputPins.size() <= 1)
174 {
175 ✗ CreateInputPin("SyncIn", Pin::Type::Object, { "TimeSync" });
176 }
177 }
178 ✗ }
179
180 ✗ bool NAV::UartPacketConverter::initialize()
181 {
182 LOG_TRACE("{}: called", nameId());
183
184 ✗ _lastSyncInCnt = 0;
185 ✗ _lastSyncOutCnt = 0;
186 ✗ _syncOutCntCorr = 0;
187 ✗ _syncInCntCorr = 0;
188
189 ✗ return true;
190 }
191
192 ✗ void NAV::UartPacketConverter::receiveObs(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */)
193 {
194 ✗ auto uartPacket = std::static_pointer_cast<const UartPacket>(queue.extract_front());
195
196 ✗ std::shared_ptr<NodeData> convertedData = nullptr;
197 ✗ if (_outputType == OutputType_UbloxObs)
198 {
199 ✗ auto obs = std::make_shared<UbloxObs>();
200 ✗ auto packet = uartPacket->raw;
201 ✗ if (!vendor::ublox::decryptUbloxObs(obs, packet, nameId())) { return; };
202 ✗ convertedData = obs;
203 ✗ }
204 ✗ else if (_outputType == OutputType_WiFiObs)
205 {
206 ✗ auto obs = std::make_shared<WiFiObs>();
207 ✗ auto packet = uartPacket->raw;
208
209 ✗ if (!vendor::espressif::decryptWiFiObs(obs, packet, nameId()))
210 {
211 ✗ LOG_WARN("{}: Decoding WiFi Obs failed", nameId());
212 ✗ return;
213 };
214 // TODO: This code does not work currently. Needs debugging
215 // if (_syncInPin && inputPins.at(INPUT_PORT_INDEX_SYNC_IN).isPinLinked())
216 // {
217 // if (auto timeSyncMaster = getInputValue<const NAV::VectorNavSensor::TimeSync>(INPUT_PORT_INDEX_SYNC_IN);
218 // timeSyncMaster && !timeSyncMaster->v->ppsTime.empty())
219 // {
220 // if (_lastSyncInCnt > obs->timeOutputs.syncInCnt) // reset of the slave
221 // {
222 // LOG_DEBUG("{}: Slave reset during time sync", nameId());
223 // _syncOutCntCorr = 0;
224 // _syncInCntCorr = timeSyncMaster->v->syncOutCnt;
225 // }
226 // else if (_lastSyncOutCnt > timeSyncMaster->v->syncOutCnt) // reset of the master
227 // {
228 // LOG_DEBUG("{}: Master reset during time sync", nameId());
229 // _syncInCntCorr = 0;
230 // _syncOutCntCorr = obs->timeOutputs.syncInCnt;
231 // }
232 // else if (_lastSyncOutCnt == 0 && timeSyncMaster->v->syncOutCnt > 1) // slave counter started later
233 // {
234 // LOG_DEBUG("{}: Slave counter started later", nameId());
235 // _syncInCntCorr = timeSyncMaster->v->syncOutCnt;
236 // }
237 // else if (_lastSyncOutCnt == 0 && obs->timeOutputs.syncInCnt > 1) // master counter started later
238 // {
239 // LOG_DEBUG("{}: Master counter started later", nameId());
240 // _syncOutCntCorr = obs->timeOutputs.syncInCnt;
241 // }
242 // _lastSyncOutCnt = timeSyncMaster->v->syncOutCnt;
243 // _lastSyncInCnt = obs->timeOutputs.syncInCnt;
244 // int64_t syncCntDiff = obs->timeOutputs.syncInCnt + _syncInCntCorr - timeSyncMaster->v->syncOutCnt - _syncOutCntCorr;
245 // obs->insTime = timeSyncMaster->v->ppsTime + std::chrono::microseconds(obs->timeOutputs.timeSyncIn)
246 // + std::chrono::seconds(syncCntDiff);
247 // // LOG_DATA("{}: Syncing time {}, pps {}, syncOutCnt {}, syncInCnt {}, syncCntDiff {}, syncInCntCorr {}, syncOutCntCorr {}",
248 // // nameId(), obs->insTime.toGPSweekTow(), timeSyncMaster->ppsTime.toGPSweekTow(),
249 // // timeSyncMaster->syncOutCnt, obs->timeOutputs.syncInCnt, syncCntDiff, _syncInCntCorr, _syncOutCntCorr);
250 // }
251 // else
252 // {
253 // return;
254 // }
255 // }
256
257 ✗ convertedData = obs;
258 ✗ }
259 else /* if (_outputType == OutputType_EmlidObs) */
260 {
261 ✗ auto obs = std::make_shared<EmlidObs>();
262 ✗ auto packet = uartPacket->raw;
263 ✗ vendor::emlid::decryptEmlidObs(obs, packet);
264 ✗ convertedData = obs;
265 ✗ }
266
267 ✗ if (!convertedData) { return; }
268
269 ✗ if (convertedData->insTime.empty())
270 {
271 ✗ convertedData->insTime = util::time::GetCurrentInsTime();
272 }
273
274 ✗ invokeCallbacks(OUTPUT_PORT_INDEX_CONVERTED, convertedData);
275 ✗ }
276