INSTINCT Code Coverage Report


Directory: src/
File: Nodes/Converter/IMU/VectorNavBinaryConverter.cpp
Date: 2025-06-02 15:19:59
Exec Total Coverage
Lines: 123 759 16.2%
Functions: 9 16 56.2%
Branches: 146 1175 12.4%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "VectorNavBinaryConverter.hpp"
10
11 #include <cmath>
12
13 #include "Navigation/Time/InsTime.hpp"
14 #include "NodeData/Baro/BaroPressObs.hpp"
15 #include "util/Logger.hpp"
16
17 #include "internal/NodeManager.hpp"
18 namespace nm = NAV::NodeManager;
19 #include "internal/FlowManager.hpp"
20
21 #include "internal/gui/widgets/EnumCombo.hpp"
22
23 #include "Navigation/Transformations/CoordinateFrames.hpp"
24 #include "Navigation/Transformations/Units.hpp"
25
26 /// @brief Scale factor to kPa to hPa
27 constexpr double SCALE_FACTOR_KILO2HECTOPASCAL = 10;
28
29 144 NAV::VectorNavBinaryConverter::VectorNavBinaryConverter()
30
2/4
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 144 times.
✗ Branch 5 not taken.
144 : Node(typeStatic())
31 {
32 LOG_TRACE("{}: called", name);
33 144 _hasConfig = true;
34 144 _guiConfigDefaultWindowSize = { 350, 123 };
35
36
4/8
✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 144 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 144 times.
✓ Branch 10 taken 144 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
576 nm::CreateOutputPin(this, "ImuObs", Pin::Type::Flow, { NAV::ImuObsWDelta::type() });
37
38
4/8
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 144 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 144 times.
✓ Branch 9 taken 144 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
432 nm::CreateInputPin(this, "BinaryOutput", Pin::Type::Flow, { NAV::VectorNavBinaryOutput::type() }, &VectorNavBinaryConverter::receiveObs);
39 432 }
40
41 352 NAV::VectorNavBinaryConverter::~VectorNavBinaryConverter()
42 {
43 LOG_TRACE("{}: called", nameId());
44 352 }
45
46 256 std::string NAV::VectorNavBinaryConverter::typeStatic()
47 {
48
1/2
✓ Branch 1 taken 256 times.
✗ Branch 2 not taken.
512 return "VectorNavBinaryConverter";
49 }
50
51 std::string NAV::VectorNavBinaryConverter::type() const
52 {
53 return typeStatic();
54 }
55
56 112 std::string NAV::VectorNavBinaryConverter::category()
57 {
58
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
224 return "Converter";
59 }
60
61 void NAV::VectorNavBinaryConverter::guiConfig()
62 {
63 if (gui::widgets::EnumCombo(fmt::format("Output Type##{}", size_t(id)).c_str(), _outputType))
64 {
65 LOG_DEBUG("{}: Output Type changed to {}", nameId(), to_string(_outputType));
66 if (_outputType == OutputType::ImuObs)
67 {
68 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::ImuObs::type() };
69 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::ImuObs::type();
70 }
71 else if (_outputType == OutputType::ImuObsWDelta)
72 {
73 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::ImuObsWDelta::type() };
74 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::ImuObsWDelta::type();
75 }
76 else if (_outputType == OutputType::BaroPressObs)
77 {
78 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::BaroPressObs::type() };
79 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::BaroPressObs::type();
80 }
81 else if (_outputType == OutputType::PosVelAtt)
82 {
83 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::PosVelAtt::type() };
84 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::PosVelAtt::type();
85 }
86 else if (_outputType == OutputType::GnssObs)
87 {
88 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::GnssObs::type() };
89 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::GnssObs::type();
90 }
91
92 for (auto& link : outputPins.front().links)
93 {
94 if (auto* connectedPin = link.getConnectedPin())
95 {
96 outputPins.front().recreateLink(*connectedPin);
97 }
98 }
99
100 flow::ApplyChanges();
101 }
102 if (_outputType == OutputType::ImuObsWDelta || _outputType == OutputType::ImuObs)
103 {
104 if (ImGui::Checkbox(fmt::format("Use compensated data##{}", size_t(id)).c_str(), &_useCompensatedData))
105 {
106 LOG_DEBUG("{}: _useCompensatedData changed to {}", nameId(), _useCompensatedData);
107 flow::ApplyChanges();
108 }
109 }
110 else if (_outputType == OutputType::PosVelAtt)
111 {
112 if (auto posVelSource = static_cast<int>(_posVelSource);
113 ImGui::Combo(fmt::format("Data Source##{}", size_t(id)).c_str(), &posVelSource, "Best\0INS\0GNSS 1\0GNSS 2\0\0"))
114 {
115 _posVelSource = static_cast<decltype(_posVelSource)>(posVelSource);
116 LOG_DEBUG("{}: _posVelSource changed to {}", nameId(), fmt::underlying(_posVelSource));
117 flow::ApplyChanges();
118 }
119 if (ImGui::Checkbox(fmt::format("Force static##{}", size_t(id)).c_str(), &_forceStatic))
120 {
121 LOG_DEBUG("{}: _forceStatic changed to {}", nameId(), _forceStatic);
122 flow::ApplyChanges();
123 }
124 }
125 }
126
127 [[nodiscard]] json NAV::VectorNavBinaryConverter::save() const
128 {
129 LOG_TRACE("{}: called", nameId());
130
131 json j;
132
133 j["outputType"] = _outputType;
134 j["posVelSource"] = _posVelSource;
135 j["forceStatic"] = _forceStatic;
136 j["useCompensatedData"] = _useCompensatedData;
137
138 return j;
139 }
140
141 32 void NAV::VectorNavBinaryConverter::restore(json const& j)
142 {
143 LOG_TRACE("{}: called", nameId());
144
145
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 if (j.contains("outputType"))
146 {
147 32 j.at("outputType").get_to(_outputType);
148
149
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 if (!outputPins.empty())
150 {
151
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (_outputType == OutputType::ImuObsWDelta)
152 {
153
3/6
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 16 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
32 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::ImuObsWDelta::type() };
154
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
16 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::ImuObsWDelta::type();
155 }
156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 else if (_outputType == OutputType::ImuObs)
157 {
158 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::ImuObs::type() };
159 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::ImuObs::type();
160 }
161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 else if (_outputType == OutputType::BaroPressObs)
162 {
163 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::BaroPressObs::type() };
164 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::BaroPressObs::type();
165 }
166
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 else if (_outputType == OutputType::PosVelAtt)
167 {
168
3/6
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 16 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
32 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::PosVelAtt::type() };
169
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
16 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::PosVelAtt::type();
170 }
171 else if (_outputType == OutputType::GnssObs)
172 {
173 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::GnssObs::type() };
174 outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::GnssObs::type();
175 }
176 }
177 }
178
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 if (j.contains("posVelSource"))
179 {
180 32 j.at("posVelSource").get_to(_posVelSource);
181 }
182
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 if (j.contains("forceStatic"))
183 {
184 32 _forceStatic = j.at("forceStatic");
185 }
186
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 if (j.contains("useCompensatedData"))
187 {
188 32 _useCompensatedData = j.at("useCompensatedData");
189 }
190 64 }
191
192 96 bool NAV::VectorNavBinaryConverter::initialize()
193 {
194 LOG_TRACE("{}: called", nameId());
195
196 96 _posVelAtt__init = nullptr;
197
198 96 return true;
199 }
200
201 28384 void NAV::VectorNavBinaryConverter::receiveObs(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */)
202 {
203
1/2
✓ Branch 1 taken 28384 times.
✗ Branch 2 not taken.
28384 auto vnObs = std::static_pointer_cast<const VectorNavBinaryOutput>(queue.extract_front());
204
205 28384 std::shared_ptr<const NodeData> convertedData = nullptr;
206
207
2/2
✓ Branch 0 taken 25776 times.
✓ Branch 1 taken 2608 times.
28384 if (_outputType == OutputType::ImuObsWDelta)
208 {
209
1/2
✓ Branch 1 taken 25776 times.
✗ Branch 2 not taken.
25776 convertedData = convert2ImuObsWDelta(vnObs);
210 }
211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2608 times.
2608 else if (_outputType == OutputType::ImuObs)
212 {
213 convertedData = convert2ImuObs(vnObs);
214 }
215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2608 times.
2608 else if (_outputType == OutputType::BaroPressObs)
216 {
217 convertedData = convert2BaroPressObs(vnObs);
218 }
219
1/2
✓ Branch 0 taken 2608 times.
✗ Branch 1 not taken.
2608 else if (_outputType == OutputType::PosVelAtt)
220 {
221
1/2
✓ Branch 1 taken 2608 times.
✗ Branch 2 not taken.
2608 convertedData = convert2PosVelAtt(vnObs);
222 }
223 else if (_outputType == OutputType::GnssObs)
224 {
225 convertedData = convert2GnssObs(vnObs);
226 }
227
228
1/2
✓ Branch 1 taken 28384 times.
✗ Branch 2 not taken.
28384 if (convertedData)
229 {
230
1/2
✓ Branch 1 taken 28384 times.
✗ Branch 2 not taken.
28384 invokeCallbacks(OUTPUT_PORT_INDEX_CONVERTED, convertedData);
231 }
232 28384 }
233
234 25776 std::shared_ptr<const NAV::ImuObsWDelta> NAV::VectorNavBinaryConverter::convert2ImuObsWDelta(const std::shared_ptr<const VectorNavBinaryOutput>& vnObs) const // NOLINT(readability-convert-member-functions-to-static)
235 {
236
1/2
✓ Branch 2 taken 25776 times.
✗ Branch 3 not taken.
25776 auto imuObs = std::make_shared<ImuObsWDelta>(vnObs->imuPos);
237
238
2/6
✗ Branch 2 not taken.
✓ Branch 3 taken 25776 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 25776 times.
✗ Branch 9 not taken.
25776 if (vnObs->gnss1Outputs || vnObs->gnss2Outputs) // If there is no GNSS data selected in the vnSensor, Imu messages should still be sent out. The VN-100 will not provide any data otherwise.
239 {
240 25776 if (!vnObs->timeOutputs
241
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25776 times.
✗ Branch 6 not taken.
25776 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
242
1/2
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
25776 || !vnObs->timeOutputs->timeStatus.dateOk()
243
1/2
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
25776 || !vnObs->timeOutputs->timeStatus.timeOk()
244
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25776 times.
✗ Branch 6 not taken.
25776 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)
245
4/8
✓ Branch 0 taken 25776 times.
✗ Branch 1 not taken.
✓ Branch 5 taken 25776 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 25776 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 25776 times.
51552 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK))
246 {
247 return nullptr;
248 }
249
1/2
✓ Branch 7 taken 25776 times.
✗ Branch 8 not taken.
25776 imuObs->insTime = InsTime(InsTime_GPSweekTow(0, static_cast<int32_t>(vnObs->timeOutputs->gpsWeek), static_cast<double>(vnObs->timeOutputs->gpsTow) * 1e-9L));
250 }
251 else
252 {
253 // VN-100 vnObs->insTime is set from
254 // - 'timeSyncMaster->ppsTime + timeSyncIn' when working together with the VN-310E or
255 // - the computer time
256 imuObs->insTime = vnObs->insTime;
257 }
258
259 25776 bool accelFound = false;
260 25776 bool gyroFound = false;
261 25776 bool dThetaFound = false;
262 25776 bool dVelFound = false;
263
1/2
✓ Branch 2 taken 25776 times.
✗ Branch 3 not taken.
25776 if (vnObs->imuOutputs)
264 {
265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25776 times.
25776 if (!_useCompensatedData)
266 {
267 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG)
268 {
269 imuObs->p_magneticField = vnObs->imuOutputs->uncompMag.cast<double>();
270 }
271 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL)
272 {
273 imuObs->p_acceleration = vnObs->imuOutputs->uncompAccel.cast<double>();
274 accelFound = true;
275 }
276 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO)
277 {
278 imuObs->p_angularRate = vnObs->imuOutputs->uncompGyro.cast<double>();
279 gyroFound = true;
280 }
281 }
282 else
283 {
284
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25776 times.
✗ Branch 6 not taken.
25776 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG)
285 {
286
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 25776 times.
✗ Branch 8 not taken.
25776 imuObs->p_magneticField = vnObs->imuOutputs->mag.cast<double>();
287 }
288
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25776 times.
✗ Branch 6 not taken.
25776 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL)
289 {
290
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 25776 times.
✗ Branch 8 not taken.
25776 imuObs->p_acceleration = vnObs->imuOutputs->accel.cast<double>();
291 25776 accelFound = true;
292 }
293
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25776 times.
✗ Branch 6 not taken.
25776 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE)
294 {
295
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 25776 times.
✗ Branch 8 not taken.
25776 imuObs->p_angularRate = vnObs->imuOutputs->angularRate.cast<double>();
296 25776 gyroFound = true;
297 }
298 }
299
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25776 times.
✗ Branch 6 not taken.
25776 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP)
300 {
301 25776 imuObs->temperature = vnObs->imuOutputs->temp;
302 }
303
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25776 times.
✗ Branch 6 not taken.
25776 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA)
304 {
305 25776 imuObs->dtime = vnObs->imuOutputs->deltaTime;
306
3/6
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 25776 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 25776 times.
✗ Branch 11 not taken.
25776 imuObs->dtheta = deg2rad(vnObs->imuOutputs->deltaTheta.cast<double>());
307 25776 dThetaFound = true;
308 }
309
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25776 times.
✗ Branch 6 not taken.
25776 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL)
310 {
311
2/4
✓ Branch 3 taken 25776 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 25776 times.
✗ Branch 8 not taken.
25776 imuObs->dvel = vnObs->imuOutputs->deltaV.cast<double>();
312 25776 dVelFound = true;
313 }
314 }
315
316
4/8
✓ Branch 0 taken 25776 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25776 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25776 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25776 times.
✗ Branch 7 not taken.
25776 if (accelFound && gyroFound && dThetaFound && dVelFound)
317 {
318 25776 return imuObs;
319 }
320
321 LOG_ERROR("{}: Conversion failed. Need {} acceleration and gyroscope measurements and deltaTheta and deltaVel in the input data.",
322 nameId(), _useCompensatedData ? "compensated" : "uncompensated");
323 return nullptr;
324 25776 }
325
326 std::shared_ptr<const NAV::ImuObs> NAV::VectorNavBinaryConverter::convert2ImuObs(const std::shared_ptr<const VectorNavBinaryOutput>& vnObs) const // NOLINT(readability-convert-member-functions-to-static)
327 {
328 auto imuObs = std::make_shared<ImuObs>(vnObs->imuPos);
329
330 if (vnObs->gnss1Outputs || vnObs->gnss2Outputs) // If there is no GNSS data selected in the vnSensor, Imu messages should still be sent out. The VN-100 will not provide any data otherwise.
331 {
332 if (!vnObs->timeOutputs
333 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
334 || !vnObs->timeOutputs->timeStatus.dateOk()
335 || !vnObs->timeOutputs->timeStatus.timeOk()
336 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)
337 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK))
338 {
339 return nullptr;
340 }
341 imuObs->insTime = InsTime(InsTime_GPSweekTow(0, static_cast<int32_t>(vnObs->timeOutputs->gpsWeek), static_cast<double>(vnObs->timeOutputs->gpsTow) * 1e-9L));
342 }
343 else
344 {
345 // VN-100 vnObs->insTime is set from
346 // - 'timeSyncMaster->ppsTime + timeSyncIn' when working together with the VN-310E or
347 // - the computer time
348 imuObs->insTime = vnObs->insTime;
349 }
350
351 bool accelFound = false;
352 bool gyroFound = false;
353 if (vnObs->imuOutputs)
354 {
355 if (!_useCompensatedData)
356 {
357 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG)
358 {
359 imuObs->p_magneticField = vnObs->imuOutputs->uncompMag.cast<double>();
360 }
361 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL)
362 {
363 imuObs->p_acceleration = vnObs->imuOutputs->uncompAccel.cast<double>();
364 accelFound = true;
365 }
366 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO)
367 {
368 imuObs->p_angularRate = vnObs->imuOutputs->uncompGyro.cast<double>();
369 gyroFound = true;
370 }
371 }
372 else
373 {
374 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG)
375 {
376 imuObs->p_magneticField = vnObs->imuOutputs->mag.cast<double>();
377 }
378 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL)
379 {
380 imuObs->p_acceleration = vnObs->imuOutputs->accel.cast<double>();
381 accelFound = true;
382 }
383 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE)
384 {
385 imuObs->p_angularRate = vnObs->imuOutputs->angularRate.cast<double>();
386 gyroFound = true;
387 }
388 }
389 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP)
390 {
391 imuObs->temperature = vnObs->imuOutputs->temp;
392 }
393 }
394
395 if (accelFound && gyroFound)
396 {
397 return imuObs;
398 }
399
400 LOG_ERROR("{}: Conversion failed. Need {} acceleration and gyroscope measurements in the input data.", nameId(), _useCompensatedData ? "compensated" : "uncompensated");
401 return nullptr;
402 }
403
404 std::shared_ptr<const NAV::BaroPressObs> NAV::VectorNavBinaryConverter::convert2BaroPressObs(const std::shared_ptr<const VectorNavBinaryOutput>& vnObs) const // NOLINT(readability-convert-member-functions-to-static)
405 {
406 auto baroPressObs = std::make_shared<BaroPressObs>();
407
408 if (vnObs->gnss1Outputs || vnObs->gnss2Outputs) // If there is no GNSS data selected in the vnSensor, Baro messages should still be sent out. The VN-100 will not provide any data otherwise.
409 {
410 if (!vnObs->timeOutputs
411 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
412 || !vnObs->timeOutputs->timeStatus.dateOk()
413 || !vnObs->timeOutputs->timeStatus.timeOk()
414 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)
415 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK))
416 {
417 return nullptr;
418 }
419 baroPressObs->insTime = InsTime(InsTime_GPSweekTow(0, static_cast<int32_t>(vnObs->timeOutputs->gpsWeek), static_cast<double>(vnObs->timeOutputs->gpsTow) * 1e-9L));
420 }
421 else
422 {
423 // VN-100 vnObs->insTime is set from
424 // - 'timeSyncMaster->ppsTime + timeSyncIn' when working together with the VN-310E or
425 // - the computer time
426 baroPressObs->insTime = vnObs->insTime;
427 }
428
429 bool baroFound = false;
430 if (vnObs->imuOutputs)
431 {
432 if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES)
433 {
434 baroPressObs->baro_pressure = SCALE_FACTOR_KILO2HECTOPASCAL * static_cast<double>(vnObs->imuOutputs->pres);
435 baroFound = true;
436 }
437
438 // if (vnObs->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP)
439 // {
440 // baroPressObs->temperature = vnObs->imuOutputs->temp;
441 // }
442 }
443
444 if (baroFound)
445 {
446 return baroPressObs;
447 }
448
449 LOG_ERROR("{}: Conversion failed. No barometer pressure data found in the input data.", nameId());
450 return nullptr;
451 }
452
453 2608 std::shared_ptr<const NAV::PosVelAtt> NAV::VectorNavBinaryConverter::convert2PosVelAtt(const std::shared_ptr<const VectorNavBinaryOutput>& vnObs) // NOLINT(readability-convert-member-functions-to-static)
454 {
455 2608 std::optional<Eigen::Quaterniond> n_Quat_b;
456 2608 std::optional<Eigen::Vector3d> e_position;
457 2608 std::optional<Eigen::Vector3d> lla_position;
458 2608 std::optional<Eigen::Vector3d> n_velocity;
459
460
1/2
✓ Branch 2 taken 2608 times.
✗ Branch 3 not taken.
2608 if (vnObs->attitudeOutputs)
461 {
462
2/4
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2608 times.
2608 if (vnObs->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION)
463 {
464 n_Quat_b = vnObs->attitudeOutputs->qtn.cast<double>();
465 }
466
2/4
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2608 times.
✗ Branch 6 not taken.
2608 else if (vnObs->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL)
467 {
468
3/6
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2608 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2608 times.
✗ Branch 10 not taken.
2608 Eigen::Vector3d ypr = deg2rad(vnObs->attitudeOutputs->ypr.cast<double>());
469
4/8
✓ Branch 1 taken 2608 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2608 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2608 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2608 times.
✗ Branch 11 not taken.
2608 n_Quat_b = trafo::n_Quat_b(ypr(2), ypr(1), ypr(0));
470 }
471 else if (vnObs->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM)
472 {
473 n_Quat_b = vnObs->attitudeOutputs->dcm.cast<double>();
474 }
475 }
476
477
1/2
✓ Branch 1 taken 2608 times.
✗ Branch 2 not taken.
2608 auto posVelAttObs = std::make_shared<PosVelAtt>();
478
479 if ((_posVelSource == PosVelSource_Best || _posVelSource == PosVelSource_Ins)
480
1/2
✓ Branch 2 taken 2608 times.
✗ Branch 3 not taken.
2608 && vnObs->insOutputs
481
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2608 times.
✓ Branch 5 taken 2608 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 2608 times.
7824 && (vnObs->insOutputs->insStatus.mode() == NAV::vendor::vectornav::InsStatus::Mode::Aligning
482
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 2608 times.
2608 || vnObs->insOutputs->insStatus.mode() == NAV::vendor::vectornav::InsStatus::Mode::Tracking))
483 {
484 if (!vnObs->timeOutputs
485 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
486 || !vnObs->timeOutputs->timeStatus.dateOk()
487 || !vnObs->timeOutputs->timeStatus.timeOk()
488 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)
489 || !(vnObs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK))
490 {
491 return nullptr;
492 }
493
494 posVelAttObs->insTime = InsTime(InsTime_GPSweekTow(0, static_cast<int32_t>(vnObs->timeOutputs->gpsWeek), static_cast<double>(vnObs->timeOutputs->gpsTow) * 1e-9L));
495
496 if (vnObs->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA)
497 {
498 lla_position = { deg2rad(vnObs->insOutputs->posLla(0)),
499 deg2rad(vnObs->insOutputs->posLla(1)),
500 vnObs->insOutputs->posLla(2) };
501 }
502 if (vnObs->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF)
503 {
504 e_position = vnObs->insOutputs->posEcef;
505 }
506
507 if (vnObs->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED)
508 {
509 n_velocity = vnObs->insOutputs->velNed.cast<double>();
510 }
511 else if ((vnObs->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF)
512 && (e_position.has_value() || lla_position.has_value()))
513 {
514 Eigen::Vector3d lla = lla_position.has_value() ? lla_position.value() : trafo::ecef2lla_WGS84(e_position.value());
515 n_velocity = trafo::n_Quat_e(lla(0), lla(1)) * vnObs->insOutputs->velEcef.cast<double>();
516 }
517 else if ((vnObs->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY)
518 && n_Quat_b.has_value())
519 {
520 n_velocity = n_Quat_b.value() * vnObs->insOutputs->velBody.cast<double>();
521 }
522 }
523
524 if ((_posVelSource == PosVelSource_Best || _posVelSource == PosVelSource_Gnss1)
525
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2608 times.
✓ Branch 4 taken 2608 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2608 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2608 times.
✗ Branch 11 not taken.
2608 && vnObs->gnss1Outputs && vnObs->gnss1Outputs->fix >= 2)
526 {
527 2608 if (!vnObs->gnss1Outputs
528
1/2
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
2608 || !vnObs->gnss1Outputs->timeInfo.status.timeOk()
529
3/6
✓ Branch 0 taken 2608 times.
✗ Branch 1 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2608 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2608 times.
5216 || !vnObs->gnss1Outputs->timeInfo.status.dateOk())
530 {
531 return nullptr;
532 }
533
534
1/2
✓ Branch 7 taken 2608 times.
✗ Branch 8 not taken.
2608 posVelAttObs->insTime = InsTime(InsTime_GPSweekTow(0, static_cast<int32_t>(vnObs->gnss1Outputs->week), static_cast<double>(vnObs->gnss1Outputs->tow) * 1e-9L));
535
536
3/6
✓ Branch 1 taken 2608 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2608 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2608 times.
✗ Branch 7 not taken.
2608 if (!e_position.has_value() && !lla_position.has_value())
537 {
538
2/4
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2608 times.
✗ Branch 6 not taken.
2608 if (vnObs->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA)
539 {
540
1/2
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
2608 lla_position = { deg2rad(vnObs->gnss1Outputs->posLla(0)),
541
1/2
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
2608 deg2rad(vnObs->gnss1Outputs->posLla(1)),
542
2/4
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2608 times.
✗ Branch 7 not taken.
2608 vnObs->gnss1Outputs->posLla(2) };
543 }
544
2/4
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2608 times.
2608 if (vnObs->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF)
545 {
546 e_position = vnObs->gnss1Outputs->posEcef;
547 }
548 }
549
550
1/2
✓ Branch 1 taken 2608 times.
✗ Branch 2 not taken.
2608 if (!n_velocity.has_value())
551 {
552
2/4
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2608 times.
✗ Branch 6 not taken.
2608 if (vnObs->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED)
553 {
554
2/4
✓ Branch 3 taken 2608 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2608 times.
✗ Branch 7 not taken.
2608 n_velocity = vnObs->gnss1Outputs->velNed.cast<double>();
555 }
556 else if ((vnObs->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF)
557 && (e_position.has_value() || lla_position.has_value()))
558 {
559 Eigen::Vector3d lla = lla_position.has_value() ? lla_position.value() : trafo::ecef2lla_WGS84(e_position.value());
560 n_velocity = trafo::n_Quat_e(lla(0), lla(1)) * vnObs->gnss1Outputs->velEcef.cast<double>();
561 }
562 }
563 }
564 if ((_posVelSource == PosVelSource_Best || _posVelSource == PosVelSource_Gnss2)
565
3/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2608 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2608 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 2608 times.
2608 && vnObs->gnss2Outputs && vnObs->gnss2Outputs->fix >= 2)
566 {
567 if (!vnObs->gnss2Outputs
568 || !vnObs->gnss2Outputs->timeInfo.status.timeOk()
569 || !vnObs->gnss2Outputs->timeInfo.status.dateOk())
570 {
571 return nullptr;
572 }
573
574 posVelAttObs->insTime = InsTime(InsTime_GPSweekTow(0, static_cast<int32_t>(vnObs->gnss2Outputs->week), static_cast<double>(vnObs->gnss2Outputs->tow) * 1e-9L));
575
576 if (!e_position.has_value() && !lla_position.has_value())
577 {
578 if (vnObs->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA)
579 {
580 lla_position = { deg2rad(vnObs->gnss2Outputs->posLla(0)),
581 deg2rad(vnObs->gnss2Outputs->posLla(1)),
582 vnObs->gnss2Outputs->posLla(2) };
583 }
584 if (vnObs->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF)
585 {
586 e_position = vnObs->gnss2Outputs->posEcef;
587 }
588 }
589
590 if (!n_velocity.has_value())
591 {
592 if (vnObs->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED)
593 {
594 n_velocity = vnObs->gnss2Outputs->velNed.cast<double>();
595 }
596 else if ((vnObs->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF)
597 && (e_position.has_value() || lla_position.has_value()))
598 {
599 Eigen::Vector3d lla = lla_position.has_value() ? lla_position.value() : trafo::ecef2lla_WGS84(e_position.value());
600 n_velocity = trafo::n_Quat_e(lla(0), lla(1)) * vnObs->gnss2Outputs->velEcef.cast<double>();
601 }
602 }
603 }
604
605
4/8
✓ Branch 1 taken 2608 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2608 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2608 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2608 times.
✗ Branch 10 not taken.
2608 if ((e_position.has_value() || lla_position.has_value()) && n_velocity.has_value())
606 {
607
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2608 times.
2608 if (e_position.has_value())
608 {
609 posVelAttObs->setPosition_e(e_position.value());
610 }
611 else
612 {
613
2/4
✓ Branch 2 taken 2608 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2608 times.
✗ Branch 6 not taken.
2608 posVelAttObs->setPosition_lla(lla_position.value());
614 }
615
2/4
✓ Branch 2 taken 2608 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2608 times.
✗ Branch 6 not taken.
2608 posVelAttObs->setVelocity_n(n_velocity.value());
616
617
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2608 times.
2608 if (!n_Quat_b.has_value())
618 {
619 LOG_DEBUG("{}: Conversion succeeded but has no attitude info.", nameId());
620 }
621 else
622 {
623
2/4
✓ Branch 2 taken 2608 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2608 times.
✗ Branch 6 not taken.
2608 posVelAttObs->setAttitude_n_Quat_b(n_Quat_b.value());
624 }
625
626
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 2592 times.
2608 if (_posVelAtt__init == nullptr)
627 {
628 16 _posVelAtt__init = posVelAttObs;
629 }
630
631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2608 times.
2608 if (_forceStatic)
632 {
633 posVelAttObs->setPosition_e(_posVelAtt__init->e_position());
634 posVelAttObs->setVelocity_n(Eigen::Vector3d::Zero());
635 posVelAttObs->setAttitude_n_Quat_b(_posVelAtt__init->n_Quat_b());
636 }
637
638 2608 return posVelAttObs;
639 }
640
641 LOG_ERROR("{}: Conversion failed. No position or velocity data found in the input data.", nameId());
642 return nullptr;
643 2608 }
644
645 std::shared_ptr<const NAV::GnssObs> NAV::VectorNavBinaryConverter::convert2GnssObs(const std::shared_ptr<const VectorNavBinaryOutput>& vnObs)
646 {
647 auto gnssObs = std::make_shared<GnssObs>();
648
649 if (!vnObs->gnss1Outputs
650 || !vnObs->gnss1Outputs->timeInfo.status.timeOk()
651 || !vnObs->gnss1Outputs->timeInfo.status.dateOk())
652 {
653 return nullptr;
654 }
655
656 gnssObs->insTime = InsTime(InsTime_GPSweekTow(0, static_cast<int32_t>(vnObs->gnss1Outputs->raw.week), vnObs->gnss1Outputs->raw.tow));
657
658 if (vnObs->gnss1Outputs)
659 {
660 if (vnObs->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS)
661 {
662 for (const auto& satRaw : vnObs->gnss1Outputs->raw.satellites)
663 {
664 bool skipMeasurement = false;
665 SatelliteSystem satSys = SatSys_None;
666 switch (satRaw.sys)
667 {
668 case vendor::vectornav::SatSys::GPS:
669 satSys = GPS;
670 break;
671 case vendor::vectornav::SatSys::SBAS:
672 satSys = SBAS;
673 break;
674 case vendor::vectornav::SatSys::Galileo:
675 satSys = GAL;
676 break;
677 case vendor::vectornav::SatSys::BeiDou:
678 satSys = BDS;
679 break;
680 case vendor::vectornav::SatSys::IMES:
681 LOG_TRACE("VectorNav SatRawElement satellite system '{}' is not supported yet. Skipping measurement.", satRaw.sys);
682 skipMeasurement = true;
683 break;
684 case vendor::vectornav::SatSys::QZSS:
685 satSys = QZSS;
686 break;
687 case vendor::vectornav::SatSys::GLONASS:
688 satSys = GLO;
689 break;
690 default: // IRNSS not in vectorNav
691 LOG_TRACE("VectorNav SatRawElement satellite system '{}' is not supported yet. Skipping measurement.", satRaw.sys);
692 skipMeasurement = true;
693 break;
694 }
695
696 Frequency frequency = Freq_None;
697 Code code;
698 switch (SatelliteSystem_(satSys))
699 {
700 case GPS:
701 switch (satRaw.freq)
702 {
703 case vendor::vectornav::RawMeas::SatRawElement::Freq::L1:
704 frequency = G01;
705 switch (satRaw.chan)
706 {
707 case vendor::vectornav::RawMeas::SatRawElement::Chan::P_Code:
708 code = Code::G1P;
709 break;
710 case vendor::vectornav::RawMeas::SatRawElement::Chan::CA_Code:
711 code = Code::G1C;
712 break;
713 case vendor::vectornav::RawMeas::SatRawElement::Chan::Y_Code:
714 code = Code::G1Y;
715 break;
716 case vendor::vectornav::RawMeas::SatRawElement::Chan::M_Code:
717 code = Code::G1M;
718 break;
719 case vendor::vectornav::RawMeas::SatRawElement::Chan::Codeless:
720 code = Code::G1N;
721 break;
722 case vendor::vectornav::RawMeas::SatRawElement::Chan::M_Chan:
723 code = Code::G1S;
724 break;
725 case vendor::vectornav::RawMeas::SatRawElement::Chan::L_Chan:
726 code = Code::G1L;
727 break;
728 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
729 code = Code::G1X;
730 break;
731 case vendor::vectornav::RawMeas::SatRawElement::Chan::Z_Tracking:
732 code = Code::G1W;
733 break;
734 default:
735 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
736 skipMeasurement = true;
737 break;
738 }
739 break;
740 case vendor::vectornav::RawMeas::SatRawElement::Freq::L2:
741 frequency = G02;
742 switch (satRaw.chan)
743 {
744 case vendor::vectornav::RawMeas::SatRawElement::Chan::P_Code:
745 code = Code::G2P;
746 break;
747 case vendor::vectornav::RawMeas::SatRawElement::Chan::CA_Code:
748 code = Code::G2C;
749 break;
750 case vendor::vectornav::RawMeas::SatRawElement::Chan::SemiCodeless:
751 code = Code::G2D;
752 break;
753 case vendor::vectornav::RawMeas::SatRawElement::Chan::Y_Code:
754 code = Code::G2Y;
755 break;
756 case vendor::vectornav::RawMeas::SatRawElement::Chan::M_Code:
757 code = Code::G2M;
758 break;
759 case vendor::vectornav::RawMeas::SatRawElement::Chan::Codeless:
760 code = Code::G2N;
761 break;
762 case vendor::vectornav::RawMeas::SatRawElement::Chan::M_Chan:
763 code = Code::G2S;
764 break;
765 case vendor::vectornav::RawMeas::SatRawElement::Chan::L_Chan:
766 code = Code::G2L;
767 break;
768 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
769 code = Code::G2X;
770 break;
771 case vendor::vectornav::RawMeas::SatRawElement::Chan::Z_Tracking:
772 code = Code::G2W;
773 break;
774 default:
775 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
776 skipMeasurement = true;
777 break;
778 }
779 break;
780 case vendor::vectornav::RawMeas::SatRawElement::Freq::L5:
781 frequency = G05;
782 switch (satRaw.chan)
783 {
784 case vendor::vectornav::RawMeas::SatRawElement::Chan::I_Chan:
785 code = Code::G5I;
786 break;
787 case vendor::vectornav::RawMeas::SatRawElement::Chan::Q_Chan:
788 code = Code::G5Q;
789 break;
790 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
791 code = Code::G5X;
792 break;
793 default:
794 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
795 skipMeasurement = true;
796 break;
797 }
798 break;
799 default:
800 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq);
801 skipMeasurement = true;
802 break;
803 }
804 break;
805 case SBAS:
806 switch (satRaw.freq)
807 {
808 case vendor::vectornav::RawMeas::SatRawElement::Freq::L1:
809 frequency = S01;
810 switch (satRaw.chan)
811 {
812 case vendor::vectornav::RawMeas::SatRawElement::Chan::CA_Code:
813 code = Code::S1C;
814 break;
815 default:
816 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
817 skipMeasurement = true;
818 break;
819 }
820 break;
821 case vendor::vectornav::RawMeas::SatRawElement::Freq::L5:
822 frequency = S05;
823 switch (satRaw.chan)
824 {
825 case vendor::vectornav::RawMeas::SatRawElement::Chan::I_Chan:
826 code = Code::S5I;
827 break;
828 case vendor::vectornav::RawMeas::SatRawElement::Chan::Q_Chan:
829 code = Code::S5Q;
830 break;
831 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
832 code = Code::S5X;
833 break;
834 default:
835 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
836 skipMeasurement = true;
837 break;
838 }
839 break;
840 default:
841 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq);
842 skipMeasurement = true;
843 break;
844 }
845 break;
846 case GAL:
847 switch (satRaw.freq)
848 {
849 case vendor::vectornav::RawMeas::SatRawElement::Freq::L1:
850 frequency = E01;
851 switch (satRaw.chan)
852 {
853 case vendor::vectornav::RawMeas::SatRawElement::Chan::CA_Code:
854 code = Code::E1C;
855 break;
856 case vendor::vectornav::RawMeas::SatRawElement::Chan::A_Chan:
857 code = Code::E1A;
858 break;
859 case vendor::vectornav::RawMeas::SatRawElement::Chan::B_Chan:
860 code = Code::E1B;
861 break;
862 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
863 code = Code::E1X;
864 break;
865 case vendor::vectornav::RawMeas::SatRawElement::Chan::ABC:
866 code = Code::E1Z;
867 break;
868 default:
869 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
870 skipMeasurement = true;
871 break;
872 }
873 break;
874 case vendor::vectornav::RawMeas::SatRawElement::Freq::L5:
875 frequency = E08;
876 switch (satRaw.chan)
877 {
878 case vendor::vectornav::RawMeas::SatRawElement::Chan::I_Chan:
879 code = Code::E8I;
880 break;
881 case vendor::vectornav::RawMeas::SatRawElement::Chan::Q_Chan:
882 code = Code::E8Q;
883 break;
884 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
885 code = Code::E8X;
886 break;
887 default:
888 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
889 skipMeasurement = true;
890 break;
891 }
892 break;
893 case vendor::vectornav::RawMeas::SatRawElement::Freq::E6:
894 frequency = E06;
895 switch (satRaw.chan)
896 {
897 case vendor::vectornav::RawMeas::SatRawElement::Chan::B_Chan:
898 code = Code::E6B;
899 break;
900 case vendor::vectornav::RawMeas::SatRawElement::Chan::CA_Code:
901 code = Code::E6C;
902 break;
903 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
904 code = Code::E6X;
905 break;
906 default:
907 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
908 skipMeasurement = true;
909 break;
910 }
911 break;
912 case vendor::vectornav::RawMeas::SatRawElement::Freq::E5a:
913 frequency = E05;
914 switch (satRaw.chan)
915 {
916 case vendor::vectornav::RawMeas::SatRawElement::Chan::I_Chan:
917 code = Code::E5I;
918 break;
919 case vendor::vectornav::RawMeas::SatRawElement::Chan::Q_Chan:
920 code = Code::E5Q;
921 break;
922 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
923 code = Code::E5X;
924 break;
925 default:
926 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
927 skipMeasurement = true;
928 break;
929 }
930 break;
931 case vendor::vectornav::RawMeas::SatRawElement::Freq::E5b:
932 frequency = E07;
933 switch (satRaw.chan)
934 {
935 case vendor::vectornav::RawMeas::SatRawElement::Chan::I_Chan:
936 code = Code::E7I;
937 break;
938 case vendor::vectornav::RawMeas::SatRawElement::Chan::Q_Chan:
939 code = Code::E7Q;
940 break;
941 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
942 code = Code::E7X;
943 break;
944 default:
945 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
946 skipMeasurement = true;
947 break;
948 }
949 break;
950 default:
951 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq);
952 skipMeasurement = true;
953 break;
954 }
955 break;
956 case BDS:
957 switch (satRaw.freq)
958 {
959 case vendor::vectornav::RawMeas::SatRawElement::Freq::L1:
960 frequency = B01;
961 switch (satRaw.chan)
962 {
963 case vendor::vectornav::RawMeas::SatRawElement::Chan::I_Chan:
964 code = Code::B2I;
965 break;
966 case vendor::vectornav::RawMeas::SatRawElement::Chan::Q_Chan:
967 code = Code::B2Q;
968 break;
969 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
970 code = Code::B2X;
971 break;
972 default:
973 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
974 skipMeasurement = true;
975 break;
976 }
977 break;
978 case vendor::vectornav::RawMeas::SatRawElement::Freq::E6:
979 frequency = B06;
980 switch (satRaw.chan)
981 {
982 case vendor::vectornav::RawMeas::SatRawElement::Chan::A_Chan:
983 code = Code::B6A;
984 break;
985 case vendor::vectornav::RawMeas::SatRawElement::Chan::I_Chan:
986 code = Code::B6I;
987 break;
988 case vendor::vectornav::RawMeas::SatRawElement::Chan::Q_Chan:
989 code = Code::B6Q;
990 break;
991 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
992 code = Code::B6X;
993 break;
994 default:
995 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
996 skipMeasurement = true;
997 break;
998 }
999 break;
1000 case vendor::vectornav::RawMeas::SatRawElement::Freq::E5b:
1001 frequency = B08;
1002 switch (satRaw.chan)
1003 {
1004 case vendor::vectornav::RawMeas::SatRawElement::Chan::I_Chan:
1005 code = Code::B7I;
1006 break;
1007 case vendor::vectornav::RawMeas::SatRawElement::Chan::Q_Chan:
1008 code = Code::B7Q;
1009 break;
1010 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
1011 code = Code::B7X;
1012 break;
1013 default:
1014 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
1015 skipMeasurement = true;
1016 break;
1017 }
1018 break;
1019 default:
1020 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq);
1021 skipMeasurement = true;
1022 break;
1023 }
1024 break;
1025 case QZSS:
1026 switch (satRaw.freq)
1027 {
1028 case vendor::vectornav::RawMeas::SatRawElement::Freq::L1:
1029 frequency = J01;
1030 switch (satRaw.chan)
1031 {
1032 case vendor::vectornav::RawMeas::SatRawElement::Chan::CA_Code:
1033 code = Code::J1C;
1034 break;
1035 case vendor::vectornav::RawMeas::SatRawElement::Chan::M_Chan:
1036 code = Code::J1S;
1037 break;
1038 case vendor::vectornav::RawMeas::SatRawElement::Chan::L_Chan:
1039 code = Code::J1L;
1040 break;
1041 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
1042 code = Code::J1X;
1043 break;
1044 default:
1045 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
1046 skipMeasurement = true;
1047 break;
1048 }
1049 break;
1050 case vendor::vectornav::RawMeas::SatRawElement::Freq::L2:
1051 frequency = J02;
1052 switch (satRaw.chan)
1053 {
1054 case vendor::vectornav::RawMeas::SatRawElement::Chan::M_Chan:
1055 code = Code::J2S;
1056 break;
1057 case vendor::vectornav::RawMeas::SatRawElement::Chan::L_Chan:
1058 code = Code::J2L;
1059 break;
1060 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
1061 code = Code::J2X;
1062 break;
1063 default:
1064 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
1065 skipMeasurement = true;
1066 break;
1067 }
1068 break;
1069 case vendor::vectornav::RawMeas::SatRawElement::Freq::L5:
1070 frequency = J05;
1071 switch (satRaw.chan)
1072 {
1073 case vendor::vectornav::RawMeas::SatRawElement::Chan::I_Chan:
1074 code = Code::J5I;
1075 break;
1076 case vendor::vectornav::RawMeas::SatRawElement::Chan::Q_Chan:
1077 code = Code::J5Q;
1078 break;
1079 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
1080 code = Code::J5X;
1081 break;
1082 default:
1083 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
1084 skipMeasurement = true;
1085 break;
1086 }
1087 break;
1088 case vendor::vectornav::RawMeas::SatRawElement::Freq::E6:
1089 frequency = J06;
1090 switch (satRaw.chan)
1091 {
1092 case vendor::vectornav::RawMeas::SatRawElement::Chan::M_Chan:
1093 code = Code::J6S;
1094 break;
1095 case vendor::vectornav::RawMeas::SatRawElement::Chan::L_Chan:
1096 code = Code::J6L;
1097 break;
1098 case vendor::vectornav::RawMeas::SatRawElement::Chan::BC_Chan:
1099 code = Code::J6X;
1100 break;
1101 default:
1102 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
1103 skipMeasurement = true;
1104 break;
1105 }
1106 break;
1107 default:
1108 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq);
1109 skipMeasurement = true;
1110 break;
1111 }
1112 break;
1113 case GLO:
1114 switch (satRaw.freq)
1115 {
1116 case vendor::vectornav::RawMeas::SatRawElement::Freq::L1:
1117 frequency = R01;
1118 switch (satRaw.chan)
1119 {
1120 case vendor::vectornav::RawMeas::SatRawElement::Chan::CA_Code:
1121 code = Code::R1C;
1122 break;
1123 case vendor::vectornav::RawMeas::SatRawElement::Chan::P_Code:
1124 code = Code::R1P;
1125 break;
1126 default:
1127 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
1128 skipMeasurement = true;
1129 break;
1130 }
1131 break;
1132 case vendor::vectornav::RawMeas::SatRawElement::Freq::L2:
1133 frequency = R02;
1134 switch (satRaw.chan)
1135 {
1136 case vendor::vectornav::RawMeas::SatRawElement::Chan::CA_Code:
1137 code = Code::R2C;
1138 break;
1139 case vendor::vectornav::RawMeas::SatRawElement::Chan::P_Code:
1140 code = Code::R2P;
1141 break;
1142 default:
1143 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' channel '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq, satRaw.chan);
1144 skipMeasurement = true;
1145 break;
1146 }
1147 break;
1148 default:
1149 LOG_TRACE("VectorNav SatRawElement satellite system '{}' frequency '{}' is not supported yet. Skipping measurement.", satRaw.sys, satRaw.freq);
1150 skipMeasurement = true;
1151 break;
1152 }
1153 break;
1154 case IRNSS: // IRNSS not in vectorNav
1155 case SatSys_None:
1156 skipMeasurement = true;
1157 break;
1158 }
1159
1160 if (skipMeasurement)
1161 {
1162 continue;
1163 }
1164
1165 (*gnssObs)(SatSigId(code, satRaw.svId)).pseudorange = { .value = satRaw.pr };
1166 (*gnssObs)(SatSigId(code, satRaw.svId)).carrierPhase = { .value = satRaw.cp };
1167 (*gnssObs)(SatSigId(code, satRaw.svId)).doppler = satRaw.dp;
1168 (*gnssObs)(SatSigId(code, satRaw.svId)).CN0 = satRaw.cno;
1169
1170 // LLI has not been implemented yet, but can be calculated from vendor::vectornav::RawMeas::SatRawElement::Flags
1171 // (*gnssObs)[{ frequency, satRaw.svId }].LLI = ...
1172 }
1173 }
1174 }
1175
1176 return gnssObs;
1177 }
1178
1179 const char* NAV::to_string(NAV::VectorNavBinaryConverter::OutputType value)
1180 {
1181 switch (value)
1182 {
1183 case NAV::VectorNavBinaryConverter::OutputType::ImuObs:
1184 return "ImuObs";
1185 case NAV::VectorNavBinaryConverter::OutputType::ImuObsWDelta:
1186 return "ImuObsWDelta";
1187 case NAV::VectorNavBinaryConverter::OutputType::BaroPressObs:
1188 return "BaroPressObs";
1189 case NAV::VectorNavBinaryConverter::OutputType::PosVelAtt:
1190 return "PosVelAtt";
1191 case NAV::VectorNavBinaryConverter::OutputType::GnssObs:
1192 return "GnssObs";
1193 case NAV::VectorNavBinaryConverter::OutputType::COUNT:
1194 return "";
1195 }
1196 return "";
1197 }
1198