INSTINCT Code Coverage Report


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