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 |