INSTINCT Code Coverage Report


Directory: src/
File: Nodes/DataLogger/GNSS/RinexObsLogger.cpp
Date: 2025-11-25 23:34:18
Exec Total Coverage
Lines: 152 323 47.1%
Functions: 12 16 75.0%
Branches: 192 832 23.1%

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 "RinexObsLogger.hpp"
10
11 #include <chrono>
12 #include <string>
13 #include "Navigation/GNSS/Core/SatelliteSystem.hpp"
14 #include <fmt/chrono.h>
15 #include <fmt/format.h>
16 using namespace fmt::literals; // NOLINT(google-build-using-namespace)
17
18 #include "internal/gui/widgets/imgui_ex.hpp"
19 #include "internal/FlowManager.hpp"
20
21 #include "internal/gui/widgets/EnumComboWithTooltip.hpp"
22 #include "internal/gui/widgets/HelpMarker.hpp"
23
24 #include "NodeData/GNSS/GnssObs.hpp"
25
26 #include "Nodes/DataProvider/GNSS/FileReader/RinexObsFile.hpp"
27
28 #include "util/Logger.hpp"
29
30 126 NAV::RinexObsLogger::RinexObsLogger()
31
5/10
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 126 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 126 times.
✗ Branch 12 not taken.
✓ Branch 16 taken 126 times.
✗ Branch 17 not taken.
126 : Node(typeStatic())
32 {
33 LOG_TRACE("{}: called", name);
34
35 126 _fileType = FileType::ASCII;
36
37 126 _hasConfig = true;
38 126 _guiConfigDefaultWindowSize = { 643, 728 };
39
40
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
126 _dynamicInputPins.addPin(this);
41 126 }
42
43 276 NAV::RinexObsLogger::~RinexObsLogger()
44 {
45 LOG_TRACE("{}: called", nameId());
46 276 }
47
48 240 std::string NAV::RinexObsLogger::typeStatic()
49 {
50
1/2
✓ Branch 1 taken 240 times.
✗ Branch 2 not taken.
480 return "RinexObsLogger";
51 }
52
53 std::string NAV::RinexObsLogger::type() const
54 {
55 return typeStatic();
56 }
57
58 114 std::string NAV::RinexObsLogger::category()
59 {
60
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
228 return "Data Logger";
61 }
62
63 void NAV::RinexObsLogger::guiConfig()
64 {
65 if (_dynamicInputPins.ShowGuiWidgets(size_t(id), inputPins, this, {}))
66 {
67 flow::ApplyChanges();
68 }
69
70 constexpr float COL1_WIDTH = 470.0F;
71
72 const auto now = std::chrono::system_clock::now();
73 ImGui::SetNextItemWidth(COL1_WIDTH);
74 if (FileWriter::guiConfig(fmt::format(".obs,.rnx,.{:%y}O", now).c_str(), { ".obs", ".rnx", fmt::format(".{:%y}O", now) }, size_t(id), nameId()))
75 {
76 flow::ApplyChanges();
77 doDeinitialize();
78 }
79
80 if (ImGui::CollapsingHeader(fmt::format("General##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
81 {
82 if (ImGui::BeginTable(fmt::format("Table1##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
83 {
84 ImGui::TableNextColumn();
85 ImGui::BeginDisabled();
86 ImGui::SetNextItemWidth(COL1_WIDTH);
87 if (ImGui::BeginCombo(fmt::format("##Version {}", size_t(id)).c_str(), fmt::format("{}", _header.version).c_str()))
88 {
89 for (const auto& version : _supportedVersions)
90 {
91 const bool is_selected = _header.version == version;
92 if (ImGui::Selectable(fmt::format("{}##Version {}", version, size_t(id)).c_str(), is_selected))
93 {
94 _header.version = version;
95 flow::ApplyChanges();
96 }
97 if (is_selected) { ImGui::SetItemDefaultFocus(); }
98 }
99 ImGui::EndCombo();
100 }
101 ImGui::EndDisabled();
102 ImGui::TableNextColumn();
103 ImGui::TextUnformatted("Version");
104
105 ImGui::TableNextColumn();
106 ImGui::SetNextItemWidth(COL1_WIDTH);
107 if (ImGui::InputTextL(fmt::format("##Run By {}", size_t(id)).c_str(), &_header.runBy, 20))
108 {
109 flow::ApplyChanges();
110 }
111 ImGui::TableNextColumn();
112 ImGui::TextUnformatted("Run By");
113
114 ImGui::TableNextColumn();
115 ImGui::SetNextItemWidth(COL1_WIDTH);
116 if (ImGui::InputTextL(fmt::format("##Observer {}", size_t(id)).c_str(), &_header.observer, 20))
117 {
118 flow::ApplyChanges();
119 }
120 ImGui::TableNextColumn();
121 ImGui::TextUnformatted("Observer");
122
123 ImGui::TableNextColumn();
124 ImGui::SetNextItemWidth(COL1_WIDTH);
125 if (ImGui::InputTextL(fmt::format("##Agency {}", size_t(id)).c_str(), &_header.agency, 40))
126 {
127 flow::ApplyChanges();
128 }
129 ImGui::TableNextColumn();
130 ImGui::TextUnformatted("Agency");
131
132 ImGui::EndTable();
133 }
134 }
135
136 if (ImGui::CollapsingHeader(fmt::format("Comments##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
137 {
138 std::vector<size_t> commentsToRemove;
139 if (ImGui::BeginTable(fmt::format("Table2##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
140 {
141 for (size_t i = 0; i < _header.comments.size(); i++)
142 {
143 ImGui::TableNextRow();
144 ImGui::TableNextColumn();
145 auto& comment = _header.comments.at(i);
146 float startPos = ImGui::GetCursorPosX();
147 if (ImGui::Button(fmt::format("X##Remove comment {} {}", i, size_t(id)).c_str()))
148 {
149 commentsToRemove.push_back(i);
150 }
151 ImGui::SameLine();
152 ImGui::SetNextItemWidth(COL1_WIDTH - (ImGui::GetCursorPosX() - startPos));
153 if (ImGui::InputTextL(fmt::format("##Comment {} {}", i, size_t(id)).c_str(), &comment, 60))
154 {
155 flow::ApplyChanges();
156 }
157 }
158 ImGui::EndTable();
159 }
160 for (const size_t& idx : commentsToRemove)
161 {
162 _header.comments.erase(std::next(_header.comments.begin(), static_cast<int>(idx)));
163 flow::ApplyChanges();
164 }
165 if (ImGui::Button(fmt::format("Add##Comment {}", size_t(id)).c_str()))
166 {
167 _header.comments.emplace_back();
168 flow::ApplyChanges();
169 }
170 }
171
172 if (ImGui::CollapsingHeader(fmt::format("Marker##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
173 {
174 if (ImGui::BeginTable(fmt::format("Table3##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
175 {
176 ImGui::TableNextColumn();
177 ImGui::SetNextItemWidth(COL1_WIDTH);
178 if (gui::widgets::EnumComboWithToolTip(fmt::format("##Marker Type {}", size_t(id)).c_str(), _header.markerType))
179 {
180 flow::ApplyChanges();
181 }
182 if (_header.markerType != vendor::RINEX::ObsHeader::MarkerTypes::USER_DEFINED) { ImGui::BeginDisabled(); }
183 ImGui::TableNextColumn();
184 ImGui::TextUnformatted("Type");
185
186 ImGui::TableNextColumn();
187 ImGui::SetNextItemWidth(COL1_WIDTH);
188 if (ImGui::InputTextL(fmt::format("##Marker User Type {}", size_t(id)).c_str(), &_header.markerTypeUser, 20))
189 {
190 flow::ApplyChanges();
191 }
192 if (_header.markerType != vendor::RINEX::ObsHeader::MarkerTypes::USER_DEFINED) { ImGui::EndDisabled(); }
193 ImGui::TableNextColumn();
194 ImGui::TextUnformatted("User Type");
195 ImGui::SameLine();
196 ImGui::Dummy(ImVec2(ImGui::GetContentRegionAvail().x, 0.0F));
197
198 ImGui::TableNextColumn();
199 ImGui::SetNextItemWidth(COL1_WIDTH);
200 if (ImGui::InputTextL(fmt::format("##Marker Name {}", size_t(id)).c_str(), &_header.markerName, 60))
201 {
202 flow::ApplyChanges();
203 }
204 ImGui::TableNextColumn();
205 ImGui::TextUnformatted("Name");
206
207 ImGui::TableNextColumn();
208 ImGui::SetNextItemWidth(COL1_WIDTH);
209 if (ImGui::InputTextL(fmt::format("##Marker Number {}", size_t(id)).c_str(), &_header.markerNumber, 20))
210 {
211 flow::ApplyChanges();
212 }
213 ImGui::TableNextColumn();
214 ImGui::TextUnformatted("Number");
215
216 ImGui::EndTable();
217 }
218 }
219
220 if (ImGui::CollapsingHeader(fmt::format("Receiver##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
221 {
222 if (ImGui::BeginTable(fmt::format("Table4##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
223 {
224 ImGui::TableNextColumn();
225 ImGui::SetNextItemWidth(COL1_WIDTH);
226 if (ImGui::InputTextL(fmt::format("##Receiver Number {}", size_t(id)).c_str(), &_header.receiverNumber, 20))
227 {
228 flow::ApplyChanges();
229 }
230 ImGui::TableNextColumn();
231 ImGui::TextUnformatted("Number");
232
233 ImGui::TableNextColumn();
234 ImGui::SetNextItemWidth(COL1_WIDTH);
235 if (ImGui::InputTextL(fmt::format("##Receiver Type {}", size_t(id)).c_str(), &_header.receiverType, 20))
236 {
237 flow::ApplyChanges();
238 }
239 ImGui::TableNextColumn();
240 ImGui::TextUnformatted("Type");
241
242 ImGui::TableNextColumn();
243 ImGui::SetNextItemWidth(COL1_WIDTH);
244 if (ImGui::InputTextL(fmt::format("##Receiver Version {}", size_t(id)).c_str(), &_header.receiverVersion, 20))
245 {
246 flow::ApplyChanges();
247 }
248 ImGui::TableNextColumn();
249 ImGui::TextUnformatted("Version");
250
251 ImGui::EndTable();
252 }
253 }
254
255 if (ImGui::CollapsingHeader(fmt::format("Antenna##{}", size_t(id)).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
256 {
257 if (ImGui::BeginTable(fmt::format("Table5##{}", size_t(id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit))
258 {
259 ImGui::TableNextColumn();
260 ImGui::SetNextItemWidth(COL1_WIDTH);
261 if (ImGui::InputTextL(fmt::format("##Antenna Number {}", size_t(id)).c_str(), &_header.antennaNumber, 20))
262 {
263 flow::ApplyChanges();
264 }
265 ImGui::TableNextColumn();
266 ImGui::TextUnformatted("Number");
267
268 ImGui::TableNextColumn();
269 ImGui::SetNextItemWidth(COL1_WIDTH);
270 if (ImGui::InputTextL(fmt::format("##Antenna Type {}", size_t(id)).c_str(), &_header.antennaType, 20))
271 {
272 flow::ApplyChanges();
273 }
274 ImGui::TableNextColumn();
275 ImGui::TextUnformatted("Type");
276
277 ImGui::TableNextColumn();
278 float startPos = ImGui::GetCursorPosX();
279 if (ImGui::Checkbox(fmt::format("##ApproxEnabled {}", size_t(id)).c_str(), &_header.approxPositionEnabled))
280 {
281 flow::ApplyChanges();
282 }
283 ImGui::SameLine();
284 ImGui::SetNextItemWidth(COL1_WIDTH - (ImGui::GetCursorPosX() - startPos));
285 if (!_header.approxPositionEnabled) { ImGui::BeginDisabled(); }
286 if (ImGui::InputDouble3L(fmt::format("##Approx position XYZ {}", size_t(id)).c_str(), _header.approxPositionXYZ.data(), -99999999.9999, 99999999.9999, "%.4f m"))
287 {
288 flow::ApplyChanges();
289 }
290 if (!_header.approxPositionEnabled) { ImGui::EndDisabled(); }
291 ImGui::TableNextColumn();
292 ImGui::TextUnformatted("Approx position XYZ");
293 ImGui::SameLine();
294 gui::widgets::HelpMarker("Geocentric approximate marker position\n"
295 "System: ITRS recommended\n"
296 "Optional for moving platforms");
297
298 ImGui::TableNextColumn();
299 ImGui::SetNextItemWidth(COL1_WIDTH);
300 if (ImGui::InputDouble3L(fmt::format("##Antenna delta HEN {}", size_t(id)).c_str(), _header.antennaDeltaHeightEastNorth.data(), -99999999.9999, 99999999.9999, "%.4f m"))
301 {
302 flow::ApplyChanges();
303 }
304 ImGui::TableNextColumn();
305 ImGui::TextUnformatted("Delta HEN");
306
307 ImGui::EndTable();
308 }
309 }
310 }
311
312 [[nodiscard]] json NAV::RinexObsLogger::save() const
313 {
314 LOG_TRACE("{}: called", nameId());
315
316 return {
317 { "dynamicInputPins", _dynamicInputPins },
318 { "FileWriter", FileWriter::save() },
319 { "HeaderInfo", _header },
320 };
321 }
322
323 12 void NAV::RinexObsLogger::restore(json const& j)
324 {
325 LOG_TRACE("{}: called", nameId());
326
327
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if (j.contains("dynamicInputPins")) { NAV::gui::widgets::from_json(j.at("dynamicInputPins"), _dynamicInputPins, this); }
328
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (j.contains("FileWriter")) { FileWriter::restore(j.at("FileWriter")); }
329
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (j.contains("HeaderInfo")) { j.at("HeaderInfo").get_to(_header); }
330 12 }
331
332 12 void NAV::RinexObsLogger::flush()
333 {
334 LOG_TRACE("{}: called", nameId());
335
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 _filestream.close();
336
337 LOG_DATA("{}: ", nameId());
338
339
2/4
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
12 auto fs = std::fstream(getFilepath(), std::ios::in | std::ios::out | std::ios::binary);
340
1/16
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
12 if (!fs.good()) { LOG_CRITICAL("{}: Could not open file: {}", nameId(), getFilepath()); }
341
342
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
342 while (!fs.eof())
343 {
344 342 std::string line;
345
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
342 auto pos = fs.tellg();
346
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
342 std::getline(fs, line);
347 LOG_DATA("{}: line: {}", nameId(), line);
348
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 330 times.
342 if (line.find("RINEX VERSION / TYPE", 60) != std::string::npos)
349 {
350
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 fs.seekg(pos);
351 LOG_DATA("{}: new : {}", nameId(), _header.headerLineRinexVersionType());
352
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 fs << _header.headerLineRinexVersionType();
353
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 fs.flush();
354 }
355
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 318 times.
330 else if (line.find("TIME OF LAST OBS", 60) != std::string::npos)
356 {
357
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 fs.seekg(pos);
358 LOG_DATA("{}: new : {}", nameId(), _header.headerLineTimeOfLastObs());
359
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 fs << _header.headerLineTimeOfLastObs();
360
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 fs.flush();
361 }
362
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 306 times.
318 else if (line.find("INTERVAL", 60) != std::string::npos)
363 {
364
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 fs.seekg(pos);
365 LOG_DATA("{}: new : {}", nameId(), _header.headerLineInterval());
366
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 fs << _header.headerLineInterval();
367
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 fs.flush();
368 }
369
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 294 times.
306 else if (line.find("# OF SATELLITES", 60) != std::string::npos)
370 {
371
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 fs.seekg(pos);
372 LOG_DATA("{}: new : {}", nameId(), _header.headerLineNumSatellites());
373
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 fs << _header.headerLineNumSatellites();
374
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 fs.flush();
375 }
376
3/4
✓ Branch 1 taken 294 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 282 times.
294 else if (line[0] == '>') { break; }
377 342 }
378 12 }
379
380 36 bool NAV::RinexObsLogger::initialize()
381 {
382 LOG_TRACE("{}: called", nameId());
383
384
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
36 if (!FileWriter::initialize())
385 {
386 return false;
387 }
388
389 36 _header.reset();
390
391
2/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
36 _filestream << _header.generateHeader();
392 36 _filestream.flush();
393
394 36 return true;
395 }
396
397 12 void NAV::RinexObsLogger::deinitialize()
398 {
399 LOG_TRACE("{}: called", nameId());
400
401 12 FileWriter::deinitialize();
402 12 }
403
404 126 void NAV::RinexObsLogger::pinAddCallback(Node* node)
405 {
406
5/10
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 126 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 126 times.
✓ Branch 14 taken 126 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
378 node->CreateInputPin(GnssObs::type().c_str(), Pin::Type::Flow, { GnssObs::type() }, &RinexObsLogger::writeObservation);
407 252 }
408
409 void NAV::RinexObsLogger::pinDeleteCallback(Node* node, size_t pinIdx)
410 {
411 node->DeleteInputPin(pinIdx);
412 }
413
414 13 void NAV::RinexObsLogger::updateFileHeader(TimeSystem oldTimeSys)
415 {
416 LOG_TRACE("{}: called", nameId());
417
418
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 _filestream.close();
419
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 _filestream.clear();
420
421
3/6
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
13 std::string pathTmp = getFilepath().string() + ".tmp";
422 {
423
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 auto fsTmp = std::ofstream(pathTmp, std::ios_base::trunc | std::ios_base::binary);
424
1/12
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
13 if (!fsTmp.good()) { LOG_CRITICAL("{}: Could not create temporary file: {}", nameId(), pathTmp); }
425
426
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 auto fsOld = std::ifstream(getFilepath(), std::ios_base::in);
427
1/16
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
13 if (!fsOld.good()) { LOG_CRITICAL("{}: Could not open old file: {}", nameId(), getFilepath()); }
428
429
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 fsTmp << _header.generateHeader();
430 LOG_DATA("{}: New Header\n{}", nameId(), _header.generateHeader());
431
432 13 bool dataRecords = false;
433
2/2
✓ Branch 1 taken 319 times.
✓ Branch 2 taken 13 times.
332 while (!fsOld.eof())
434 {
435 319 std::string line;
436
1/2
✓ Branch 1 taken 319 times.
✗ Branch 2 not taken.
319 std::getline(fsOld, line);
437 LOG_DATA("{}: Line: {}", nameId(), line);
438
3/4
✓ Branch 1 taken 319 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 317 times.
319 if (line[0] == '>')
439 {
440 2 dataRecords = true;
441
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (oldTimeSys == _header.timeSys)
442 {
443 LOG_DATA("{}: Read whole file", nameId());
444 fsTmp << line << '\n';
445 fsTmp << fsOld.rdbuf(); // Read whole data record at once
446 break;
447 }
448
449 LOG_DATA("{}: Read epoch [{}][{}][{}][{}][{}][{}] [{}]", nameId(), line.substr(2, 4), line.substr(7, 2), line.substr(10, 2),
450 line.substr(13, 2), line.substr(16, 2), line.substr(18, 11), line.substr(29 + 3, 3));
451
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 auto epochTime = InsTime{ static_cast<uint16_t>(std::stoi(line.substr(2, 4))), // year [1X,I4]
452
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 static_cast<uint16_t>(std::stoi(line.substr(7, 2))), // month [1X,I2.2]
453
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 static_cast<uint16_t>(std::stoi(line.substr(10, 2))), // day [1X,I2.2]
454
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 static_cast<uint16_t>(std::stoi(line.substr(13, 2))), // hour [1X,I2.2]
455
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 static_cast<uint16_t>(std::stoi(line.substr(16, 2))), // min [1X,I2.2]
456 2 std::stold(line.substr(18, 11)), // sec [F11.7,2X,I1,]
457
7/14
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 20 not taken.
10 oldTimeSys };
458
4/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
2 fsTmp << _header.epochRecordLine(epochTime, std::stoul(line.substr(29 + 3, 3))); // Num satellites I3,6X,F15.12
459 }
460
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 299 times.
317 else if (dataRecords)
461 {
462
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 fsTmp << line;
463
3/4
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
18 if (!line.empty()) { fsTmp << '\n'; }
464 }
465 319 }
466 13 }
467
3/6
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
13 std::filesystem::rename(pathTmp, getFilepath());
468
469
2/4
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
13 _filestream.open(getFilepath(), std::ios_base::app | std::ios_base::binary);
470
1/16
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
13 if (!_filestream.good()) { LOG_CRITICAL("{}: Could not open file: {}", nameId(), getFilepath()); }
471 13 }
472
473 2035 void NAV::RinexObsLogger::writeObservation(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */)
474 {
475
1/2
✓ Branch 1 taken 2035 times.
✗ Branch 2 not taken.
2035 auto obs = std::static_pointer_cast<const GnssObs>(queue.extract_front());
476 LOG_DATA("{}: [{}]", nameId(), obs->insTime.toYMDHMS(GPST));
477
478
1/2
✓ Branch 2 taken 2035 times.
✗ Branch 3 not taken.
2035 _header.interval = std::min(_header.interval, std::round(static_cast<double>((obs->insTime - _header.timeLastObs).count()) * 1e3) / 1e3);
479
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 2023 times.
2035 if (_header.timeFirstObs.empty()) { _header.timeFirstObs = obs->insTime; }
480 2035 _header.timeLastObs = obs->insTime;
481
482 2035 std::set<SatId> satellites;
483 2035 bool satelliteSystemDescriptionChanged = false;
484
2/2
✓ Branch 6 taken 130664 times.
✓ Branch 7 taken 2035 times.
132699 for (const auto& sig : obs->data)
485 {
486
1/2
✓ Branch 1 taken 130664 times.
✗ Branch 2 not taken.
130664 auto satId = sig.satSigId.toSatId();
487
1/2
✓ Branch 1 taken 130664 times.
✗ Branch 2 not taken.
130664 satellites.insert(satId);
488
1/2
✓ Branch 1 taken 130664 times.
✗ Branch 2 not taken.
130664 _header.satellites.insert(satId);
489 130664 _header.satSys |= satId.satSys;
490
491
3/4
✓ Branch 1 taken 130608 times.
✓ Branch 2 taken 56 times.
✓ Branch 4 taken 130608 times.
✗ Branch 5 not taken.
130664 if (sig.pseudorange) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::C); }
492
3/4
✓ Branch 1 taken 124399 times.
✓ Branch 2 taken 6265 times.
✓ Branch 4 taken 124399 times.
✗ Branch 5 not taken.
130664 if (sig.carrierPhase) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::L); }
493
3/4
✓ Branch 1 taken 95086 times.
✓ Branch 2 taken 35578 times.
✓ Branch 4 taken 95086 times.
✗ Branch 5 not taken.
130664 if (sig.doppler) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::D); }
494
3/4
✓ Branch 1 taken 130622 times.
✓ Branch 2 taken 42 times.
✓ Branch 4 taken 130622 times.
✗ Branch 5 not taken.
130664 if (sig.CN0) { satelliteSystemDescriptionChanged |= _header.addObsType(sig.satSigId.code, vendor::RINEX::ObsType::S); }
495 }
496
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2022 times.
2035 if (satelliteSystemDescriptionChanged)
497 {
498 13 TimeSystem oldTimeSys = _header.timeSys;
499
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 _header.timeSys = vendor::RINEX::timeSystem(_header.satSys);
500
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 updateFileHeader(oldTimeSys);
501 }
502
503
2/4
✓ Branch 3 taken 2035 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2035 times.
✗ Branch 7 not taken.
2035 _filestream << _header.epochRecordLine(obs->insTime, satellites.size());
504
505
2/2
✓ Branch 5 taken 70774 times.
✓ Branch 6 taken 2035 times.
72809 for (const auto& satId : satellites)
506 {
507 141548 _filestream << fmt::format("{0}{1:02d}", satId.satSys.toChar(),
508
5/8
✓ Branch 1 taken 542 times.
✓ Branch 2 taken 70232 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 542 times.
✓ Branch 6 taken 70774 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 70774 times.
✗ Branch 10 not taken.
141548 satId.satSys == SBAS && satId.satNum > 100 ? satId.satNum - 100 : satId.satNum);
509
1/2
✓ Branch 1 taken 70774 times.
✗ Branch 2 not taken.
70774 const auto& obsDescriptions = _header.systemObsTypes.at(satId.satSys);
510
2/2
✓ Branch 1 taken 533111 times.
✓ Branch 2 taken 70774 times.
603885 for (size_t i = 0; i < obsDescriptions.size(); i++)
511 {
512
1/2
✓ Branch 1 taken 533111 times.
✗ Branch 2 not taken.
533111 const auto& obsDesc = obsDescriptions.at(i);
513
514
1/2
✓ Branch 2 taken 533111 times.
✗ Branch 3 not taken.
533111 auto signal = std::ranges::find_if(obs->data, [&obsDesc, &satId](const auto& sig) {
515
1/2
✓ Branch 2 taken 22581641 times.
✗ Branch 3 not taken.
22581641 return sig.satSigId == SatSigId{ obsDesc.code, satId.satNum };
516 });
517
518 533111 bool obsWritten = false;
519
2/2
✓ Branch 3 taken 486147 times.
✓ Branch 4 taken 46964 times.
533111 if (signal != obs->data.end())
520 {
521
4/6
✓ Branch 0 taken 130664 times.
✓ Branch 1 taken 129775 times.
✓ Branch 2 taken 95086 times.
✓ Branch 3 taken 130622 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
486147 switch (obsDesc.type)
522 {
523 130664 case vendor::RINEX::ObsType::C:
524
5/6
✓ Branch 2 taken 130608 times.
✓ Branch 3 taken 56 times.
✓ Branch 6 taken 130608 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 130608 times.
✓ Branch 9 taken 56 times.
130664 if (signal->pseudorange && signal->pseudorange->value < 100'000'000.0)
525 {
526 261216 _filestream << fmt::format("{obs:14.3f} {SSI}",
527
1/2
✓ Branch 4 taken 130608 times.
✗ Branch 5 not taken.
130608 "obs"_a = signal->pseudorange->value,
528
7/12
✓ Branch 2 taken 10394 times.
✓ Branch 3 taken 120214 times.
✓ Branch 5 taken 10394 times.
✗ Branch 6 not taken.
✓ Branch 12 taken 130608 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 130608 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 10394 times.
✓ Branch 19 taken 120214 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
402218 "SSI"_a = signal->pseudorange->SSI == 0 ? " " : std::to_string(signal->pseudorange->SSI));
529 130608 obsWritten = true;
530 }
531 130664 break;
532 129775 case vendor::RINEX::ObsType::L:
533
5/6
✓ Branch 2 taken 124399 times.
✓ Branch 3 taken 5376 times.
✓ Branch 6 taken 124399 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 124399 times.
✓ Branch 9 taken 5376 times.
129775 if (signal->carrierPhase && signal->carrierPhase->value < 1'000'000'000.0)
534 {
535 248798 _filestream << fmt::format("{obs:14.3f}{LLI:1}{SSI:1}",
536
1/2
✓ Branch 4 taken 124399 times.
✗ Branch 5 not taken.
124399 "obs"_a = signal->carrierPhase->value,
537
6/10
✓ Branch 2 taken 124354 times.
✓ Branch 3 taken 45 times.
✓ Branch 5 taken 124354 times.
✗ Branch 6 not taken.
✓ Branch 12 taken 124399 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 124354 times.
✓ Branch 16 taken 45 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
373152 "LLI"_a = signal->carrierPhase->LLI == 0 ? " " : std::to_string(signal->carrierPhase->LLI),
538
7/12
✓ Branch 2 taken 10394 times.
✓ Branch 3 taken 114005 times.
✓ Branch 5 taken 10394 times.
✗ Branch 6 not taken.
✓ Branch 12 taken 124399 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 124399 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 10394 times.
✓ Branch 19 taken 114005 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
383591 "SSI"_a = signal->carrierPhase->SSI == 0 ? " " : std::to_string(signal->carrierPhase->SSI));
539 124399 obsWritten = true;
540 }
541 129775 break;
542 95086 case vendor::RINEX::ObsType::D:
543
1/2
✓ Branch 2 taken 95086 times.
✗ Branch 3 not taken.
95086 if (signal->doppler)
544 {
545
2/4
✓ Branch 2 taken 95086 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 95086 times.
✗ Branch 6 not taken.
190172 _filestream << fmt::format("{:14.3f} ", signal->doppler.value());
546 95086 obsWritten = true;
547 }
548 95086 break;
549 130622 case vendor::RINEX::ObsType::S:
550
1/2
✓ Branch 2 taken 130622 times.
✗ Branch 3 not taken.
130622 if (signal->CN0)
551 {
552
2/4
✓ Branch 2 taken 130622 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 130622 times.
✗ Branch 6 not taken.
261244 _filestream << fmt::format("{:14.3f} ", signal->CN0.value());
553 130622 obsWritten = true;
554 }
555 130622 break;
556 case vendor::RINEX::ObsType::I:
557 case vendor::RINEX::ObsType::X:
558 case vendor::RINEX::ObsType::Error:
559 break;
560 }
561 }
562
2/2
✓ Branch 0 taken 52396 times.
✓ Branch 1 taken 480715 times.
533111 if (!obsWritten)
563 {
564
2/4
✓ Branch 2 taken 52396 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 52396 times.
✗ Branch 7 not taken.
104792 _filestream << fmt::format("{X:16}", "X"_a = "");
565 }
566
2/2
✓ Branch 1 taken 70774 times.
✓ Branch 2 taken 462337 times.
533111 if (i == obsDescriptions.size() - 1)
567 {
568
1/2
✓ Branch 1 taken 70774 times.
✗ Branch 2 not taken.
70774 _filestream << "\n";
569 }
570 }
571 }
572 2035 }
573