| 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 "CsvLogger.hpp" | ||
| 10 | |||
| 11 | #include "NodeData/NodeData.hpp" | ||
| 12 | |||
| 13 | #include "util/Logger.hpp" | ||
| 14 | |||
| 15 | #include <iomanip> // std::setprecision | ||
| 16 | #include <regex> | ||
| 17 | |||
| 18 | #include "internal/FlowManager.hpp" | ||
| 19 | #include "NodeRegistry.hpp" | ||
| 20 | #include "internal/gui/NodeEditorApplication.hpp" | ||
| 21 | #include "util/StringUtil.hpp" | ||
| 22 | |||
| 23 | 116 | NAV::CsvLogger::CsvLogger() | |
| 24 |
4/8✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 116 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 116 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 116 times.
✗ Branch 12 not taken.
|
116 | : Node(typeStatic()) |
| 25 | { | ||
| 26 | LOG_TRACE("{}: called", name); | ||
| 27 | |||
| 28 | 116 | _fileType = FileType::ASCII; | |
| 29 | |||
| 30 | 116 | _hasConfig = true; | |
| 31 | 116 | _guiConfigDefaultWindowSize = { 380, 70 }; | |
| 32 | |||
| 33 |
4/8✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 116 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 116 times.
✓ Branch 9 taken 116 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
348 | CreateInputPin("writeObservation", Pin::Type::Flow, |
| 34 | { NodeData::type() }, | ||
| 35 | &CsvLogger::writeObservation); | ||
| 36 | 232 | } | |
| 37 | |||
| 38 | 236 | NAV::CsvLogger::~CsvLogger() | |
| 39 | { | ||
| 40 | LOG_TRACE("{}: called", nameId()); | ||
| 41 | 236 | } | |
| 42 | |||
| 43 | 230 | std::string NAV::CsvLogger::typeStatic() | |
| 44 | { | ||
| 45 |
1/2✓ Branch 1 taken 230 times.
✗ Branch 2 not taken.
|
460 | return "CsvLogger"; |
| 46 | } | ||
| 47 | |||
| 48 | ✗ | std::string NAV::CsvLogger::type() const | |
| 49 | { | ||
| 50 | ✗ | return typeStatic(); | |
| 51 | } | ||
| 52 | |||
| 53 | 114 | std::string NAV::CsvLogger::category() | |
| 54 | { | ||
| 55 |
1/2✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
|
228 | return "Data Logger"; |
| 56 | } | ||
| 57 | |||
| 58 | ✗ | void NAV::CsvLogger::guiConfig() | |
| 59 | { | ||
| 60 | ✗ | if (FileWriter::guiConfig(".csv", { ".csv" }, size_t(id), nameId())) | |
| 61 | { | ||
| 62 | ✗ | flow::ApplyChanges(); | |
| 63 | ✗ | doDeinitialize(); | |
| 64 | } | ||
| 65 | |||
| 66 | ✗ | if (CommonLog::ShowOriginInput(nameId().c_str())) | |
| 67 | { | ||
| 68 | ✗ | flow::ApplyChanges(); | |
| 69 | } | ||
| 70 | |||
| 71 | ✗ | if (ImGui::Button(fmt::format("Clear header##{}", size_t(id)).c_str())) | |
| 72 | { | ||
| 73 | ✗ | _headerLogging.clear(); | |
| 74 | } | ||
| 75 | ✗ | ImGui::SameLine(); | |
| 76 | ✗ | if (ImGui::Button(fmt::format("Select all##{}", size_t(id)).c_str())) | |
| 77 | { | ||
| 78 | ✗ | for (auto& header : _headerLogging) { header.second = true; } | |
| 79 | ✗ | flow::ApplyChanges(); | |
| 80 | } | ||
| 81 | ✗ | ImGui::SameLine(); | |
| 82 | ✗ | if (ImGui::Button(fmt::format("Deselect all##{}", size_t(id)).c_str())) | |
| 83 | { | ||
| 84 | ✗ | for (auto& header : _headerLogging) { header.second = false; } | |
| 85 | ✗ | flow::ApplyChanges(); | |
| 86 | } | ||
| 87 | ✗ | ImGui::SameLine(); | |
| 88 | ✗ | if (ImGui::Checkbox(fmt::format("Default for new##{}", size_t(id)).c_str(), &_headerLoggingDefault)) | |
| 89 | { | ||
| 90 | ✗ | flow::ApplyChanges(); | |
| 91 | } | ||
| 92 | ✗ | ImGui::SameLine(); | |
| 93 | ✗ | if (ImGui::Checkbox(fmt::format("Sort headers in GUI##{}", size_t(id)).c_str(), &_headerLoggingSortGui)) | |
| 94 | { | ||
| 95 | ✗ | flow::ApplyChanges(); | |
| 96 | } | ||
| 97 | |||
| 98 | ✗ | if (_headerLoggingRegex.empty()) { ImGui::BeginDisabled(); } | |
| 99 | ✗ | std::optional<bool> regexSelect; | |
| 100 | ✗ | if (ImGui::Button(fmt::format("Select regex##{}", size_t(id)).c_str())) | |
| 101 | { | ||
| 102 | ✗ | regexSelect = true; | |
| 103 | } | ||
| 104 | ✗ | ImGui::SameLine(); | |
| 105 | ✗ | if (ImGui::Button(fmt::format("Deselect regex##{}", size_t(id)).c_str())) | |
| 106 | { | ||
| 107 | ✗ | regexSelect = false; | |
| 108 | } | ||
| 109 | ✗ | if (regexSelect.has_value()) | |
| 110 | { | ||
| 111 | ✗ | bool anyChanged = false; | |
| 112 | try | ||
| 113 | { | ||
| 114 | ✗ | for (auto& [desc, checked] : _headerLogging) | |
| 115 | { | ||
| 116 | ✗ | std::regex self_regex(_headerLoggingRegex, | |
| 117 | ✗ | std::regex_constants::ECMAScript | std::regex_constants::icase); | |
| 118 | ✗ | if (std::regex_search(desc, self_regex) && checked != *regexSelect) | |
| 119 | { | ||
| 120 | ✗ | anyChanged = true; | |
| 121 | ✗ | checked = *regexSelect; | |
| 122 | } | ||
| 123 | ✗ | } | |
| 124 | } | ||
| 125 | ✗ | catch (const std::regex_error& e) | |
| 126 | { | ||
| 127 | ✗ | LOG_ERROR("Regex could not be parsed: {}", e.what()); | |
| 128 | ✗ | } | |
| 129 | ✗ | if (anyChanged) | |
| 130 | { | ||
| 131 | ✗ | flow::ApplyChanges(); | |
| 132 | } | ||
| 133 | } | ||
| 134 | ✗ | if (_headerLoggingRegex.empty()) { ImGui::EndDisabled(); } | |
| 135 | ✗ | ImGui::SameLine(); | |
| 136 | ✗ | ImGui::SetNextItemWidth(300.0F * gui::NodeEditorApplication::windowFontRatio()); | |
| 137 | ✗ | if (ImGui::InputText(fmt::format("##Select Regex {}", size_t(id)).c_str(), &_headerLoggingRegex)) | |
| 138 | { | ||
| 139 | ✗ | flow::ApplyChanges(); | |
| 140 | } | ||
| 141 | |||
| 142 | ✗ | if (!_headerLogging.empty()) | |
| 143 | { | ||
| 144 | ✗ | auto* headerLogging = &_headerLogging; | |
| 145 | ✗ | decltype(_headerLogging) sortedHeaderLogging; | |
| 146 | ✗ | if (_headerLoggingSortGui) | |
| 147 | { | ||
| 148 | ✗ | sortedHeaderLogging = _headerLogging; | |
| 149 | ✗ | std::ranges::sort(sortedHeaderLogging); | |
| 150 | ✗ | headerLogging = &sortedHeaderLogging; | |
| 151 | } | ||
| 152 | ✗ | int nCols = std::min((static_cast<int>(headerLogging->size()) - 1) / 5 + 1, 3); | |
| 153 | ✗ | if (ImGui::BeginChild(fmt::format("Headers Scrolling {}", size_t(id)).c_str(), ImGui::GetContentRegionAvail(), false)) | |
| 154 | { | ||
| 155 | ✗ | if (ImGui::BeginTable(fmt::format("Logging headers##{}", size_t(id)).c_str(), nCols, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
| 156 | { | ||
| 157 | ✗ | for (auto& [desc, checked] : *headerLogging) | |
| 158 | { | ||
| 159 | ✗ | ImGui::TableNextColumn(); | |
| 160 | ✗ | if (ImGui::Checkbox(fmt::format("{}##{}", desc, size_t(id)).c_str(), &checked)) | |
| 161 | { | ||
| 162 | ✗ | if (_headerLoggingSortGui) | |
| 163 | { | ||
| 164 | ✗ | if (auto iter = std::ranges::find_if(_headerLogging, [&](const std::pair<std::string, bool>& header) { | |
| 165 | ✗ | return desc == header.first; // NOLINT(clang-analyzer-core.CallAndMessage) | |
| 166 | }); | ||
| 167 | ✗ | iter != _headerLogging.end()) | |
| 168 | { | ||
| 169 | ✗ | iter->second = checked; | |
| 170 | } | ||
| 171 | } | ||
| 172 | ✗ | flow::ApplyChanges(); | |
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | ✗ | ImGui::EndTable(); | |
| 177 | } | ||
| 178 | } | ||
| 179 | ✗ | ImGui::EndChild(); | |
| 180 | ✗ | } | |
| 181 | else | ||
| 182 | { | ||
| 183 | ✗ | ImGui::TextUnformatted("Please run the flow to collect information about the available data."); | |
| 184 | } | ||
| 185 | ✗ | } | |
| 186 | |||
| 187 | ✗ | [[nodiscard]] json NAV::CsvLogger::save() const | |
| 188 | { | ||
| 189 | LOG_TRACE("{}: called", nameId()); | ||
| 190 | |||
| 191 | return { | ||
| 192 | ✗ | { "FileWriter", FileWriter::save() }, | |
| 193 | ✗ | { "header", _headerLogging }, | |
| 194 | ✗ | { "lastConnectedType", _lastConnectedType }, | |
| 195 | ✗ | { "headerLoggingRegex", _headerLoggingRegex }, | |
| 196 | ✗ | { "headerLoggingDefault", _headerLoggingDefault }, | |
| 197 | ✗ | { "headerLoggingSortGui", _headerLoggingSortGui }, | |
| 198 | ✗ | }; | |
| 199 | ✗ | } | |
| 200 | |||
| 201 | 2 | void NAV::CsvLogger::restore(json const& j) | |
| 202 | { | ||
| 203 | LOG_TRACE("{}: called", nameId()); | ||
| 204 | |||
| 205 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("FileWriter")) { FileWriter::restore(j.at("FileWriter")); } |
| 206 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("header")) { j.at("header").get_to(_headerLogging); } |
| 207 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("lastConnectedType")) { j.at("lastConnectedType").get_to(_lastConnectedType); } |
| 208 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("headerLoggingRegex")) { j.at("headerLoggingRegex").get_to(_headerLoggingRegex); } |
| 209 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("headerLoggingDefault")) { j.at("headerLoggingDefault").get_to(_headerLoggingDefault); } |
| 210 | 2 | } | |
| 211 | |||
| 212 | 2 | void NAV::CsvLogger::flush() | |
| 213 | { | ||
| 214 | 2 | _filestream.flush(); | |
| 215 | 2 | } | |
| 216 | |||
| 217 | 2 | bool NAV::CsvLogger::onCreateLink([[maybe_unused]] OutputPin& startPin, [[maybe_unused]] InputPin& endPin) | |
| 218 | { | ||
| 219 | LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id)); | ||
| 220 | |||
| 221 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (_lastConnectedType != startPin.dataIdentifier.front()) |
| 222 | { | ||
| 223 | ✗ | LOG_DEBUG("{}: [{} ==> {}] Dropping headers because last type [{}] and new type [{}]", nameId(), size_t(startPin.id), size_t(endPin.id), _lastConnectedType, startPin.dataIdentifier.front()); | |
| 224 | ✗ | _headerLogging.clear(); | |
| 225 | } | ||
| 226 | 2 | _lastConnectedType = startPin.dataIdentifier.front(); | |
| 227 | |||
| 228 | 2 | return true; | |
| 229 | } | ||
| 230 | |||
| 231 | 6 | bool NAV::CsvLogger::initialize() | |
| 232 | { | ||
| 233 | LOG_TRACE("{}: called", nameId()); | ||
| 234 | |||
| 235 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
6 | if (!FileWriter::initialize()) |
| 236 | { | ||
| 237 | ✗ | return false; | |
| 238 | } | ||
| 239 | |||
| 240 | 6 | CommonLog::initialize(); | |
| 241 | |||
| 242 | 6 | _headerWritten = false; | |
| 243 | 6 | _dynamicHeader.clear(); | |
| 244 | |||
| 245 | 6 | return true; | |
| 246 | } | ||
| 247 | |||
| 248 | 2 | void NAV::CsvLogger::deinitialize() | |
| 249 | { | ||
| 250 | LOG_TRACE("{}: called", nameId()); | ||
| 251 | |||
| 252 | 2 | FileWriter::deinitialize(); | |
| 253 | 2 | } | |
| 254 | |||
| 255 | 2 | void NAV::CsvLogger::writeHeader() | |
| 256 | { | ||
| 257 | 2 | _filestream << "Time [s],GpsCycle,GpsWeek,GpsToW [s]"; | |
| 258 | |||
| 259 | #if LOG_LEVEL <= LOG_LEVEL_TRACE | ||
| 260 | std::string headers = "Time [s],GpsCycle,GpsWeek,GpsToW [s]"; | ||
| 261 | #endif | ||
| 262 | |||
| 263 | 2 | _headerLoggingCount = 0; | |
| 264 |
2/2✓ Branch 7 taken 183 times.
✓ Branch 8 taken 2 times.
|
185 | for (const auto& [desc, enabled] : _headerLogging) |
| 265 | { | ||
| 266 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 183 times.
|
183 | if (!enabled) { continue; } |
| 267 | 183 | _headerLoggingCount++; | |
| 268 | |||
| 269 |
4/8✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 183 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 183 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 183 times.
✗ Branch 11 not taken.
|
549 | auto header = str::replaceAll_copy(desc, ",", "_"); |
| 270 | #if LOG_LEVEL <= LOG_LEVEL_TRACE | ||
| 271 | headers += "," + header; | ||
| 272 | #endif | ||
| 273 |
2/4✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 183 times.
✗ Branch 5 not taken.
|
183 | _filestream << "," << header; |
| 274 | 183 | } | |
| 275 | 2 | _filestream << std::endl; // NOLINT(performance-avoid-endl) | |
| 276 | |||
| 277 | #if LOG_LEVEL <= LOG_LEVEL_TRACE | ||
| 278 | LOG_TRACE("{}: Header written:\n{}", nameId(), headers); | ||
| 279 | #endif | ||
| 280 | |||
| 281 | 2 | _headerWritten = true; | |
| 282 | 2 | } | |
| 283 | |||
| 284 | ✗ | void NAV::CsvLogger::rewriteData(size_t oldSize, size_t newSize) | |
| 285 | { | ||
| 286 | LOG_TRACE("{}: Rewriting header, because {} new elements", nameId(), newSize - oldSize); | ||
| 287 | ✗ | FileWriter::deinitialize(); | |
| 288 | ✗ | auto tmpFilePath = getFilepath().concat("_temp"); | |
| 289 | ✗ | std::filesystem::rename(getFilepath(), tmpFilePath); | |
| 290 | ✗ | FileWriter::initialize(); | |
| 291 | ✗ | writeHeader(); | |
| 292 | |||
| 293 | ✗ | std::ifstream tmpFilestream(tmpFilePath, std::ios_base::in | std::ios_base::binary); | |
| 294 | ✗ | if (tmpFilestream.good()) | |
| 295 | { | ||
| 296 | ✗ | std::string delimiterEnd(newSize - oldSize, ','); | |
| 297 | ✗ | std::string line; | |
| 298 | ✗ | std::getline(tmpFilestream, line); // Old header | |
| 299 | ✗ | while (std::getline(tmpFilestream, line) && !tmpFilestream.eof()) | |
| 300 | { | ||
| 301 | ✗ | _filestream << line << delimiterEnd << '\n'; | |
| 302 | } | ||
| 303 | ✗ | } | |
| 304 | ✗ | if (tmpFilestream.is_open()) { tmpFilestream.close(); } | |
| 305 | ✗ | tmpFilestream.clear(); | |
| 306 | ✗ | std::filesystem::remove(tmpFilePath); | |
| 307 | ✗ | } | |
| 308 | |||
| 309 | 30 | void NAV::CsvLogger::writeObservation(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */) | |
| 310 | { | ||
| 311 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | auto obs = queue.extract_front(); |
| 312 | |||
| 313 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
2520 | auto oldHeaderLength = static_cast<size_t>(std::ranges::count_if(_headerLogging, [](const auto& header) { return header.second; })); |
| 314 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 28 times.
|
30 | if (!_headerWritten) |
| 315 | { | ||
| 316 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
|
2 | for (const auto& desc : obs->staticDataDescriptors()) |
| 317 | { | ||
| 318 | ✗ | if (auto iter = std::ranges::find_if(_headerLogging, [&](const std::pair<std::string, bool>& header) { | |
| 319 | ✗ | return desc == header.first; | |
| 320 | }); | ||
| 321 | ✗ | iter == _headerLogging.end()) | |
| 322 | { | ||
| 323 | ✗ | _headerLogging.emplace_back(desc, _headerLoggingDefault); | |
| 324 | ✗ | flow::ApplyChanges(); | |
| 325 | } | ||
| 326 | 2 | } | |
| 327 | } | ||
| 328 |
3/4✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✓ Branch 9 taken 2487 times.
✓ Branch 10 taken 30 times.
|
2518 | for (const auto& desc : obs->dynamicDataDescriptors()) |
| 329 | { | ||
| 330 |
3/4✓ Branch 1 taken 2488 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 183 times.
✓ Branch 4 taken 2305 times.
|
130474 | if (std::ranges::none_of(_dynamicHeader, [&](const auto& header) { return header == desc; })) |
| 331 | { | ||
| 332 | LOG_DATA("{}: Adding new dynamic header: {}", nameId(), desc); | ||
| 333 |
1/2✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
|
183 | _dynamicHeader.push_back(desc); |
| 334 |
1/2✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
|
183 | if (auto iter = std::ranges::find_if(_headerLogging, [&](const std::pair<std::string, bool>& header) { |
| 335 | 10270 | return desc == header.first; | |
| 336 | }); | ||
| 337 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 183 times.
|
183 | iter == _headerLogging.end()) |
| 338 | { | ||
| 339 | ✗ | _headerLogging.emplace_back(desc, _headerLoggingDefault); | |
| 340 | ✗ | flow::ApplyChanges(); | |
| 341 | } | ||
| 342 | } | ||
| 343 | 30 | } | |
| 344 | |||
| 345 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 28 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
30 | if (!_headerWritten) { writeHeader(); } |
| 346 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
|
2335 | else if (auto newHeaderLength = static_cast<size_t>(std::ranges::count_if(_headerLogging, [](const auto& header) { return header.second; })); |
| 347 | oldHeaderLength != newHeaderLength) | ||
| 348 | { | ||
| 349 | ✗ | rewriteData(oldHeaderLength, newHeaderLength); | |
| 350 | } | ||
| 351 | |||
| 352 | 30 | constexpr int gpsCyclePrecision = 3; | |
| 353 | 30 | constexpr int gpsTimePrecision = 12; | |
| 354 | 30 | constexpr int valuePrecision = 15; | |
| 355 | |||
| 356 |
1/2✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
|
30 | if (!obs->insTime.empty()) |
| 357 | { | ||
| 358 |
2/4✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30 times.
✗ Branch 8 not taken.
|
30 | _filestream << std::setprecision(valuePrecision) << std::round(calcTimeIntoRun(obs->insTime) * 1e9) / 1e9; |
| 359 | } | ||
| 360 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | _filestream << ","; |
| 361 |
1/2✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
|
30 | if (!obs->insTime.empty()) |
| 362 | { | ||
| 363 |
3/6✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 30 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 30 times.
✗ Branch 12 not taken.
|
30 | _filestream << std::fixed << std::setprecision(gpsCyclePrecision) << obs->insTime.toGPSweekTow().gpsCycle; |
| 364 | } | ||
| 365 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | _filestream << ","; |
| 366 |
1/2✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
|
30 | if (!obs->insTime.empty()) |
| 367 | { | ||
| 368 |
3/6✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 30 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 30 times.
✗ Branch 12 not taken.
|
30 | _filestream << std::defaultfloat << std::setprecision(gpsTimePrecision) << obs->insTime.toGPSweekTow().gpsWeek; |
| 369 | } | ||
| 370 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | _filestream << ","; |
| 371 |
1/2✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
|
30 | if (!obs->insTime.empty()) |
| 372 | { | ||
| 373 |
3/6✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 30 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 30 times.
✗ Branch 12 not taken.
|
30 | _filestream << std::defaultfloat << std::setprecision(gpsTimePrecision) << obs->insTime.toGPSweekTow().tow; |
| 374 | } | ||
| 375 | 30 | _filestream << std::setprecision(valuePrecision); | |
| 376 | |||
| 377 | 30 | size_t dataLogged = 0; | |
| 378 |
1/2✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
|
30 | const auto staticDataDescriptors = obs->staticDataDescriptors(); |
| 379 |
2/4✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30 times.
|
30 | for (size_t i = 0; i < obs->staticDescriptorCount(); ++i) |
| 380 | { | ||
| 381 | ✗ | const auto& desc = staticDataDescriptors.at(i); | |
| 382 | ✗ | if (auto iter = std::ranges::find_if(_headerLogging, [&](const std::pair<std::string, bool>& header) { | |
| 383 | ✗ | return desc == header.first; | |
| 384 | }); | ||
| 385 | ✗ | iter != _headerLogging.end() && !iter->second) | |
| 386 | { | ||
| 387 | ✗ | continue; | |
| 388 | } | ||
| 389 | ✗ | dataLogged++; | |
| 390 | ✗ | _filestream << ','; | |
| 391 | ✗ | if (auto val = obs->getValueAt(i)) { _filestream << *val; } | |
| 392 | } | ||
| 393 | |||
| 394 |
2/2✓ Branch 5 taken 2488 times.
✓ Branch 6 taken 30 times.
|
2520 | for (const auto& desc : _dynamicHeader) |
| 395 | { | ||
| 396 |
1/2✓ Branch 1 taken 2489 times.
✗ Branch 2 not taken.
|
2488 | if (auto iter = std::ranges::find_if(_headerLogging, [&](const std::pair<std::string, bool>& header) { |
| 397 | 127919 | return desc == header.first; | |
| 398 | }); | ||
| 399 |
3/6✓ Branch 2 taken 2490 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2490 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2490 times.
|
2489 | iter != _headerLogging.end() && !iter->second) |
| 400 | { | ||
| 401 | ✗ | continue; | |
| 402 | } | ||
| 403 | 2490 | dataLogged++; | |
| 404 |
1/2✓ Branch 1 taken 2489 times.
✗ Branch 2 not taken.
|
2490 | _filestream << ','; |
| 405 |
3/6✓ Branch 2 taken 2486 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2486 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 2490 times.
✗ Branch 10 not taken.
|
2489 | if (auto val = obs->getDynamicDataAt(desc)) { _filestream << *val; } |
| 406 | } | ||
| 407 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | for (size_t i = dataLogged; i < _headerLoggingCount; i++) |
| 408 | { | ||
| 409 | ✗ | _filestream << ','; | |
| 410 | } | ||
| 411 | |||
| 412 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | _filestream << '\n'; |
| 413 | 30 | } | |
| 414 |