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 "UbloxGnssOrbitCollector.hpp" | ||
10 | |||
11 | #include <algorithm> | ||
12 | #include <chrono> | ||
13 | #include <cstddef> | ||
14 | #include <imgui.h> | ||
15 | #include <imgui_internal.h> | ||
16 | |||
17 | #include "util/Logger.hpp" | ||
18 | #include "util/Container/STL.hpp" | ||
19 | |||
20 | #include "internal/NodeManager.hpp" | ||
21 | #include <fmt/format.h> | ||
22 | namespace nm = NAV::NodeManager; | ||
23 | #include "internal/FlowManager.hpp" | ||
24 | |||
25 | #include "Navigation/GNSS/Satellite/Ephemeris/GPSEphemeris.hpp" | ||
26 | #include "Navigation/GNSS/Satellite/Ephemeris/GalileoEphemeris.hpp" | ||
27 | #include "Navigation/GNSS/Satellite/Ephemeris/GLONASSEphemeris.hpp" | ||
28 | #include "Navigation/GNSS/Satellite/Ephemeris/BDSEphemeris.hpp" | ||
29 | #include "Navigation/GNSS/Functions.hpp" | ||
30 | #include "Navigation/Transformations/Units.hpp" | ||
31 | |||
32 | 115 | NAV::UbloxGnssOrbitCollector::UbloxGnssOrbitCollector() | |
33 |
2/4✓ Branch 1 taken 115 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 115 times.
✗ Branch 5 not taken.
|
115 | : Node(typeStatic()) |
34 | { | ||
35 | LOG_TRACE("{}: called", name); | ||
36 | 115 | _hasConfig = true; | |
37 | |||
38 |
4/8✓ Branch 1 taken 115 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 115 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 115 times.
✓ Branch 9 taken 115 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
345 | nm::CreateInputPin(this, "UbloxObs", Pin::Type::Flow, { NAV::UbloxObs::type() }, &UbloxGnssOrbitCollector::receiveObs); |
39 | |||
40 |
5/10✓ Branch 2 taken 115 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 115 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 115 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 115 times.
✓ Branch 15 taken 115 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
|
460 | nm::CreateOutputPin(this, GnssNavInfo::type().c_str(), Pin::Type::Object, { GnssNavInfo::type() }, &_gnssNavInfo); |
41 | 345 | } | |
42 | |||
43 | 232 | NAV::UbloxGnssOrbitCollector::~UbloxGnssOrbitCollector() | |
44 | { | ||
45 | LOG_TRACE("{}: called", nameId()); | ||
46 | 232 | } | |
47 | |||
48 | 229 | std::string NAV::UbloxGnssOrbitCollector::typeStatic() | |
49 | { | ||
50 |
1/2✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
|
458 | return "UbloxGnssOrbitCollector"; |
51 | } | ||
52 | |||
53 | ✗ | std::string NAV::UbloxGnssOrbitCollector::type() const | |
54 | { | ||
55 | ✗ | return typeStatic(); | |
56 | } | ||
57 | |||
58 | 114 | std::string NAV::UbloxGnssOrbitCollector::category() | |
59 | { | ||
60 |
1/2✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
|
228 | return "Converter"; |
61 | } | ||
62 | |||
63 | ✗ | void NAV::UbloxGnssOrbitCollector::guiConfig() | |
64 | { | ||
65 | ✗ | bool isDisabled = ImGui::GetCurrentContext()->CurrentItemFlags & ImGuiItemFlags_Disabled; | |
66 | |||
67 | ✗ | if (isDisabled) { ImGui::EndDisabled(); } | |
68 | ✗ | if (ImGui::BeginTable(fmt::format("{} UbloxGnssOrbitCollector", size_t(id)).c_str(), 4, | |
69 | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX)) | ||
70 | { | ||
71 | ✗ | ImGui::TableSetupColumn(""); | |
72 | ✗ | ImGui::TableSetupColumn("Received"); | |
73 | ✗ | ImGui::TableSetupColumn("Iono"); | |
74 | ✗ | ImGui::TableSetupColumn("Building"); | |
75 | ✗ | ImGui::TableHeadersRow(); | |
76 | |||
77 | ✗ | for (uint64_t sys = 0xFF; sys < static_cast<uint64_t>(0xFF) << (7 * 8); sys = sys << 8UL) | |
78 | { | ||
79 | ✗ | ImGui::TableNextRow(); | |
80 | ✗ | ImGui::TableNextColumn(); | |
81 | |||
82 | ✗ | ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); | |
83 | ✗ | SatelliteSystem satSys{ SatelliteSystem_(sys) }; | |
84 | ✗ | ImGui::TextUnformatted(fmt::format("{}", satSys).c_str()); | |
85 | |||
86 | ✗ | ImGui::TableNextColumn(); | |
87 | ✗ | size_t i = 0; | |
88 | ✗ | constexpr size_t ITEMS_PER_ROW = 4; | |
89 | ✗ | for (const auto& [satId, sat] : _gnssNavInfo.satellites()) | |
90 | { | ||
91 | ✗ | if (satId.satSys != satSys) { continue; } | |
92 | ✗ | if (i % ITEMS_PER_ROW != 0) | |
93 | { | ||
94 | ✗ | ImGui::SameLine(); | |
95 | ✗ | ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::GetStyle().ItemSpacing.x); | |
96 | ✗ | ImGui::TextUnformatted(", "); | |
97 | ✗ | ImGui::SameLine(); | |
98 | } | ||
99 | ✗ | ImGui::TextUnformatted(fmt::format("{}", satId).c_str()); | |
100 | ✗ | if (ImGui::IsItemHovered()) | |
101 | { | ||
102 | ✗ | ImGui::BeginTooltip(); | |
103 | ✗ | for (const auto& satNavData : sat.getNavigationData()) | |
104 | { | ||
105 | ✗ | ImGui::TextUnformatted(fmt::format("{}", satNavData->refTime.toYMDHMS(GPST)).c_str()); | |
106 | } | ||
107 | ✗ | ImGui::EndTooltip(); | |
108 | } | ||
109 | ✗ | i++; | |
110 | } | ||
111 | |||
112 | ✗ | ImGui::TableNextColumn(); | |
113 | ✗ | std::string iono; | |
114 | ✗ | for (const auto& correction : _gnssNavInfo.ionosphericCorrections.data()) | |
115 | { | ||
116 | ✗ | if (correction.satSys != satSys) { continue; } | |
117 | ✗ | if (!iono.empty()) { iono += ", "; } | |
118 | ✗ | iono += correction.alphaBeta == IonosphericCorrections::Alpha ? "α" : "β"; | |
119 | } | ||
120 | ✗ | ImGui::TextUnformatted(iono.c_str()); | |
121 | |||
122 | ✗ | ImGui::TableNextColumn(); | |
123 | ✗ | for (const auto& builder : _ephemerisBuilder) | |
124 | { | ||
125 | ✗ | if (builder.satId.satSys != satSys | |
126 | ✗ | || std::ranges::any_of(_gnssNavInfo.satellites(), [&](const auto& sat) { | |
127 | ✗ | if (builder.satId != sat.first) { return false; } | |
128 | ✗ | return std::ranges::any_of(sat.second.getNavigationData(), [&](const std::shared_ptr<NAV::SatNavData>& satNavData) { | |
129 | ✗ | return satNavData->refTime == builder.navData->refTime; | |
130 | ✗ | }); | |
131 | })) | ||
132 | { | ||
133 | ✗ | continue; | |
134 | } | ||
135 | |||
136 | ✗ | ImGui::TextUnformatted(fmt::format("{} ({}) frames: {}", builder.satId, builder.navData->refTime.toYMDHMS(GPST), builder.subframes).c_str()); | |
137 | } | ||
138 | ✗ | } | |
139 | |||
140 | ✗ | ImGui::EndTable(); | |
141 | } | ||
142 | ✗ | if (isDisabled) { ImGui::BeginDisabled(); } | |
143 | ✗ | } | |
144 | |||
145 | 3 | bool NAV::UbloxGnssOrbitCollector::initialize() | |
146 | { | ||
147 | LOG_TRACE("{}: called", nameId()); | ||
148 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if (!_postProcessingLock.has_value()) |
149 | { | ||
150 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | auto guard = requestOutputValueLock(OUTPUT_PORT_INDEX_GNSS_NAV_INFO); |
151 | 3 | _gnssNavInfo.reset(); | |
152 | 3 | } | |
153 | else | ||
154 | { | ||
155 | ✗ | _gnssNavInfo.reset(); | |
156 | } | ||
157 | 3 | _ephemerisBuilder.clear(); | |
158 | 3 | _lastAccessedBuilder.clear(); | |
159 | 3 | _warningsNotImplemented.clear(); | |
160 | |||
161 | 3 | if (inputPins.at(INPUT_PORT_INDEX_UBLOX_OBS).isPinLinked() | |
162 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
|
3 | && getMode() == Mode::POST_PROCESSING |
163 |
4/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
|
6 | && !_postProcessingLock.has_value()) |
164 | { | ||
165 | LOG_TRACE("{}: Setting post-processing lock", nameId()); | ||
166 | 1 | _postProcessingLock.emplace(outputPins.at(OUTPUT_PORT_INDEX_GNSS_NAV_INFO).dataAccessMutex); | |
167 | } | ||
168 | |||
169 | 3 | return true; | |
170 | } | ||
171 | |||
172 | 1 | void NAV::UbloxGnssOrbitCollector::onDeleteLink([[maybe_unused]] OutputPin& startPin, [[maybe_unused]] InputPin& endPin) | |
173 | { | ||
174 | LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id)); | ||
175 | |||
176 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (_postProcessingLock.has_value()) |
177 | { | ||
178 | 1 | _postProcessingLock.reset(); | |
179 | } | ||
180 | 1 | } | |
181 | |||
182 | 718 | NAV::UbloxGnssOrbitCollector::EphemerisBuilder& NAV::UbloxGnssOrbitCollector::getEphemerisBuilder(const SatId& satId, const InsTime& insTime, size_t IOD) | |
183 | { | ||
184 | LOG_DATA("{}: Searching for [{}] at [{}]", nameId(), satId, insTime.toYMDHMS(GPST)); | ||
185 |
2/2✓ Branch 0 taken 227 times.
✓ Branch 1 taken 491 times.
|
718 | if (IOD != 0) |
186 | { | ||
187 |
1/2✓ Branch 1 taken 227 times.
✗ Branch 2 not taken.
|
227 | _lastAccessedBuilder[satId] = IOD; |
188 | } | ||
189 | |||
190 |
1/2✓ Branch 1 taken 718 times.
✗ Branch 2 not taken.
|
718 | auto iter = std::ranges::find_if(_ephemerisBuilder, [&](const auto& builder) { |
191 |
4/4✓ Branch 1 taken 875 times.
✓ Branch 2 taken 8649 times.
✓ Branch 5 taken 671 times.
✓ Branch 6 taken 204 times.
|
9524 | return builder.satId == satId && builder.navData->refTime == insTime; |
192 | }); | ||
193 |
2/2✓ Branch 2 taken 47 times.
✓ Branch 3 taken 671 times.
|
718 | if (iter == _ephemerisBuilder.end()) |
194 | { | ||
195 | LOG_DATA("{}: Constructing new builder", nameId()); | ||
196 | |||
197 | 47 | std::shared_ptr<SatNavData> satNavData = nullptr; | |
198 |
2/9✓ Branch 1 taken 19 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
47 | switch (SatelliteSystem_(satId.satSys)) |
199 | { | ||
200 | 19 | case GPS: | |
201 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | satNavData = std::make_shared<GPSEphemeris>(insTime); |
202 | 19 | break; | |
203 | 28 | case GAL: | |
204 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | satNavData = std::make_shared<GalileoEphemeris>(insTime); |
205 | 28 | break; | |
206 | ✗ | case GLO: | |
207 | // satNavData = std::make_shared<GLONASSEphemeris>(insTime); | ||
208 | ✗ | LOG_CRITICAL("{}: GLONASS not implemented yet.", nameId()); // TODO: Not yet supported | |
209 | break; | ||
210 | ✗ | case BDS: | |
211 | // satNavData = std::make_shared<BDSEphemeris>(insTime); | ||
212 | ✗ | LOG_CRITICAL("{}: BeiDou not implemented yet.", nameId()); // TODO: Not yet supported | |
213 | break; | ||
214 | ✗ | case QZSS: | |
215 | ✗ | LOG_CRITICAL("{}: QZSS not implemented yet.", nameId()); // TODO: Not yet supported | |
216 | break; | ||
217 | ✗ | case IRNSS: | |
218 | ✗ | LOG_CRITICAL("{}: IRNSS not implemented yet.", nameId()); // TODO: Not yet supported | |
219 | break; | ||
220 | ✗ | case SBAS: | |
221 | ✗ | LOG_CRITICAL("{}: SBAS not implemented yet.", nameId()); // TODO: Not yet supported | |
222 | break; | ||
223 | ✗ | case SatSys_None: | |
224 | ✗ | LOG_CRITICAL("{}: Satellite system cannot be none.", nameId()); | |
225 | break; | ||
226 | } | ||
227 |
1/2✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
|
47 | return _ephemerisBuilder.emplace_back(satId, satNavData); |
228 | 47 | } | |
229 | |||
230 | LOG_DATA("{}: Found builder", nameId()); | ||
231 | 671 | return *iter; | |
232 | } | ||
233 | |||
234 | std::optional<std::reference_wrapper<NAV::UbloxGnssOrbitCollector::EphemerisBuilder>> | ||
235 | 1184 | NAV::UbloxGnssOrbitCollector::getEphemerisBuilder(const SatId& satId, size_t IOD) | |
236 | { | ||
237 | LOG_DATA("{}: Searching for [{}] at Issue of Data [{}]", nameId(), satId, IOD); | ||
238 |
1/2✓ Branch 1 taken 1184 times.
✗ Branch 2 not taken.
|
1184 | _lastAccessedBuilder[satId] = IOD; |
239 | |||
240 |
1/2✓ Branch 1 taken 1184 times.
✗ Branch 2 not taken.
|
1184 | auto iter = std::ranges::find_if(_ephemerisBuilder, [&](const auto& builder) { |
241 |
2/2✓ Branch 1 taken 1828 times.
✓ Branch 2 taken 20327 times.
|
22155 | if (builder.satId == satId) |
242 | { | ||
243 |
2/2✓ Branch 1 taken 262 times.
✓ Branch 2 taken 1566 times.
|
1828 | if (builder.navData->type == SatNavData::GPSEphemeris) |
244 | { | ||
245 | 262 | auto ephemeris = std::dynamic_pointer_cast<GPSEphemeris>(builder.navData); | |
246 |
3/4✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 246 times.
✓ Branch 5 taken 16 times.
|
262 | return ephemeris && ephemeris->IODE == IOD; |
247 | 262 | } | |
248 |
1/2✓ Branch 1 taken 1566 times.
✗ Branch 2 not taken.
|
1566 | if (builder.navData->type == SatNavData::GalileoEphemeris) |
249 | { | ||
250 | 1566 | auto ephemeris = std::dynamic_pointer_cast<GalileoEphemeris>(builder.navData); | |
251 |
3/4✓ Branch 1 taken 1566 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 876 times.
✓ Branch 5 taken 690 times.
|
1566 | return ephemeris && ephemeris->IODnav == IOD; |
252 | 1566 | } | |
253 | } | ||
254 | 20327 | return false; | |
255 | }); | ||
256 |
2/2✓ Branch 2 taken 1122 times.
✓ Branch 3 taken 62 times.
|
1184 | if (iter != _ephemerisBuilder.end()) |
257 | { | ||
258 | LOG_DATA("{}: Found builder", nameId()); | ||
259 | 1122 | return *iter; | |
260 | } | ||
261 | LOG_DATA("{}: Could not find builder. Ignoring subframe.", nameId()); | ||
262 | 62 | return std::nullopt; | |
263 | } | ||
264 | |||
265 | std::optional<std::reference_wrapper<NAV::UbloxGnssOrbitCollector::EphemerisBuilder>> | ||
266 | 238 | NAV::UbloxGnssOrbitCollector::getLastEphemerisBuilder(const SatId& satId) | |
267 | { | ||
268 | LOG_DATA("{}: Searching the last builder for [{}]", nameId(), satId); | ||
269 |
1/2✓ Branch 1 taken 238 times.
✗ Branch 2 not taken.
|
238 | if (_lastAccessedBuilder.contains(satId)) |
270 | { | ||
271 | 238 | return getEphemerisBuilder(satId, _lastAccessedBuilder.at(satId)); | |
272 | } | ||
273 | LOG_DATA("{}: Could not find last accessed builder. Ignoring subframe.", nameId()); | ||
274 | ✗ | return std::nullopt; | |
275 | } | ||
276 | |||
277 | 8207 | void NAV::UbloxGnssOrbitCollector::receiveObs(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */) | |
278 | { | ||
279 |
1/2✓ Branch 1 taken 8207 times.
✗ Branch 2 not taken.
|
8207 | [[maybe_unused]] auto ubloxObs = std::static_pointer_cast<const UbloxObs>(queue.extract_front()); |
280 | LOG_DATA("{}: [{}] Received UbloxObs {}-{}", nameId(), ubloxObs->insTime.toYMDHMS(GPST), | ||
281 | vendor::ublox::getStringFromMsgClass(ubloxObs->msgClass), | ||
282 | vendor::ublox::getStringFromMsgId(ubloxObs->msgClass, ubloxObs->msgId)); | ||
283 | |||
284 |
1/2✓ Branch 1 taken 8207 times.
✗ Branch 2 not taken.
|
8207 | if (ubloxObs->msgClass == ubx::UBX_CLASS_RXM) |
285 | { | ||
286 |
2/2✓ Branch 1 taken 6607 times.
✓ Branch 2 taken 1600 times.
|
8207 | if (static_cast<ubx::UbxRxmMessages>(ubloxObs->msgId) == ubx::UbxRxmMessages::UBX_RXM_SFRBX) |
287 | { | ||
288 |
1/2✓ Branch 2 taken 6607 times.
✗ Branch 3 not taken.
|
6607 | const auto& sfrbx = std::get<ubx::UbxRxmSfrbx>(ubloxObs->data); |
289 | |||
290 |
1/2✓ Branch 1 taken 6607 times.
✗ Branch 2 not taken.
|
6607 | SatelliteSystem satSys = ubx::getSatSys(sfrbx.gnssId); |
291 | 6607 | SatId satId(satSys, sfrbx.svId); | |
292 | LOG_DATA("{}: [{}][{}] Converting message", nameId(), ubloxObs->insTime.toYMDHMS(GPST), satId); | ||
293 | |||
294 |
2/9✓ Branch 1 taken 2396 times.
✓ Branch 2 taken 4211 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
6607 | switch (SatelliteSystem_(satSys)) |
295 | { | ||
296 | 2396 | case GPS: | |
297 |
1/2✓ Branch 2 taken 2396 times.
✗ Branch 3 not taken.
|
2396 | decryptGPS(satId, sfrbx, ubloxObs->insTime); |
298 | 2396 | break; | |
299 | 4211 | case GAL: | |
300 |
1/2✓ Branch 2 taken 4211 times.
✗ Branch 3 not taken.
|
4211 | decryptGalileo(satId, sfrbx, ubloxObs->insTime); |
301 | 4211 | break; | |
302 | ✗ | case GLO: | |
303 | ✗ | decryptGLONASS(satId, sfrbx, ubloxObs->insTime); | |
304 | ✗ | break; | |
305 | ✗ | case BDS: | |
306 | ✗ | decryptBeiDou(satId, sfrbx, ubloxObs->insTime); | |
307 | ✗ | break; | |
308 | ✗ | case QZSS: | |
309 | ✗ | decryptQZSS(satId, sfrbx, ubloxObs->insTime); | |
310 | ✗ | break; | |
311 | ✗ | case IRNSS: | |
312 | ✗ | decryptIRNSS(satId, sfrbx, ubloxObs->insTime); | |
313 | ✗ | break; | |
314 | ✗ | case SBAS: | |
315 | ✗ | decryptSBAS(satId, sfrbx, ubloxObs->insTime); | |
316 | ✗ | break; | |
317 | ✗ | case SatSys_None: | |
318 | ✗ | LOG_CRITICAL("{}: Satellite system cannot be none.", nameId()); | |
319 | break; | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | |||
324 | 8207 | if (_postProcessingLock.has_value() | |
325 |
3/6✓ Branch 1 taken 8207 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8207 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8207 times.
✗ Branch 7 not taken.
|
8207 | && inputPins.at(INPUT_PORT_INDEX_UBLOX_OBS).isPinLinked() |
326 |
5/10✓ Branch 0 taken 8207 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 8207 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8207 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 8207 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 8207 times.
|
16414 | && inputPins.at(INPUT_PORT_INDEX_UBLOX_OBS).link.getConnectedPin()->noMoreDataAvailable) |
327 | { | ||
328 | LOG_TRACE("{}: Post-processing lock cleared as all data read.", nameId()); | ||
329 | ✗ | _postProcessingLock.reset(); | |
330 | } | ||
331 | 8207 | } | |
332 | |||
333 | 2396 | void NAV::UbloxGnssOrbitCollector::decryptGPS(const SatId& satId, const ubx::UbxRxmSfrbx& sfrbx, const InsTime& insTime) | |
334 | { | ||
335 | // u-blox 8 / u-blox M8: Receiver description - Including protocol specification, ch. 10.2, p. 30f | ||
336 | // > For GPS L1C/A signals, there is a fairly straightforward mapping between the reported subframe | ||
337 | // > and the structure of subframe and words described in the GPS ICD. Each subframe comprises ten | ||
338 | // > data words, which are reported in the same order they are received. | ||
339 | // > | ||
340 | // > MSB LSB | ||
341 | // > 1 to 10: Pad (2 bits) Data (24 bits) Parity (6 bits) | ||
342 | // > | ||
343 | // > Note that as the GPS data words only comprise 30 bits, the 2 most significant bits in each word | ||
344 | // > reported by UBX-RXM-SFRBX are padding and should be ignored. | ||
345 | |||
346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2396 times.
|
2396 | if (sfrbx.numWords != 10) |
347 | { | ||
348 | ✗ | LOG_ERROR("{}: [{}] Received {} instead of 10 words", nameId(), satId, sfrbx.numWords); | |
349 | 1169 | return; | |
350 | } | ||
351 | |||
352 | 2396 | size_t w = 0; // Word counter | |
353 | |||
354 | // Telemetry Word | ||
355 | // 30 bits long, occurs every 6 seconds ┌ Integrity Status Flag | ||
356 | // Preamble │ ┌ Reserved | ||
357 | // 1 0 0 0 1 0 1 1 MSB TLM Message LSB │ │ Parity | ||
358 | // ┌──────┴──────┐ ┌───────────────┴──────────────────────┐ │ │ ┌──────┴────────┐ | ||
359 | // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ||
360 | LOG_DATA("{}: [{}] tlm: {} {}", nameId(), satId, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
361 | 2396 | constexpr uint8_t TLM_PREAMBLE = 0b10001011; | |
362 |
3/4✓ Branch 1 taken 2396 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1169 times.
✓ Branch 4 taken 1227 times.
|
2396 | if (static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111) != TLM_PREAMBLE) // Preamble found after the 2 padding bits |
363 | { | ||
364 | LOG_DATA("{}: [{}] Wrong telemetry word preamble. Ignoring SFRBX message.", nameId(), satId); | ||
365 | 1169 | return; | |
366 | } | ||
367 | |||
368 | // Handover Word (HOW) | ||
369 | // 30 bits long, occurs every 6 seconds anti-spoof (A-S) flag | ||
370 | // alert flag │ | ||
371 | // MSB TOW-Count Message LSB │ │ Subframe ID Parity | ||
372 | // ┌──────────────────┴────────────────────┐ │ │ ┌───┴──┐ ┌──────┴────────┐ | ||
373 | // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ||
374 | 1227 | w++; | |
375 | LOG_DATA("{}: [{}] how: {} {}", nameId(), satId, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
376 |
1/2✓ Branch 1 taken 1227 times.
✗ Branch 2 not taken.
|
1227 | auto subFrameId = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 8) & 0b111); |
377 | LOG_DATA("{}: [{}] subFrameId: {}", nameId(), satId, subFrameId); | ||
378 | |||
379 |
2/4✓ Branch 0 taken 1227 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1227 times.
|
1227 | if (subFrameId == 0 || subFrameId > 5) |
380 | { | ||
381 | ✗ | LOG_ERROR("{}: [{}] The subFrameId has to be in the range [1..=5] but it is {}", nameId(), satId, subFrameId); | |
382 | ✗ | return; | |
383 | } | ||
384 | |||
385 |
1/2✓ Branch 2 taken 1227 times.
✗ Branch 3 not taken.
|
1227 | auto gpsWeekToW = insTime.toGPSweekTow(GPST); |
386 | |||
387 | 736 | auto finishSubFrame = [&]<size_t N>(const std::shared_ptr<SatNavData>& ephemeris, size_t subFrameId, std::bitset<N>& subframesFound) { | |
388 |
2/4✓ Branch 0 taken 736 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 736 times.
✗ Branch 3 not taken.
|
736 | if (1 <= subFrameId && subFrameId <= 3) |
389 | { | ||
390 | 736 | subframesFound.set(subFrameId - 1); | |
391 | |||
392 | LOG_DATA("{}: [{}] subframesFound: {}", nameId(), satId, subframesFound); | ||
393 |
2/2✓ Branch 1 taken 698 times.
✓ Branch 2 taken 38 times.
|
736 | if (subframesFound.count() == 3) |
394 | { | ||
395 | LOG_DATA("{}: [{}] [{}] All subframes found. Updating gnnsNavInfo", nameId(), satId, ephemeris->refTime.toYMDHMS(GPST)); | ||
396 |
3/4✓ Branch 2 taken 698 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 687 times.
|
698 | if (!_gnssNavInfo.searchNavigationData(satId, ephemeris->refTime)) |
397 | { | ||
398 |
4/8✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 11 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 11 times.
✗ Branch 14 not taken.
|
11 | LOG_DEBUG("{}: Adding new ephemeris data [{}] [{}]", nameId(), satId, ephemeris->refTime.toYMDHMS(GPST)); |
399 | } | ||
400 |
1/2✓ Branch 1 taken 698 times.
✗ Branch 2 not taken.
|
698 | std::unique_lock guard(outputPins.at(OUTPUT_PORT_INDEX_GNSS_NAV_INFO).dataAccessMutex, std::defer_lock); |
401 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 698 times.
|
698 | if (!_postProcessingLock.has_value()) |
402 | { | ||
403 | ✗ | guard.lock(); | |
404 | } | ||
405 | 698 | _gnssNavInfo.satelliteSystems |= satId.satSys; | |
406 |
1/2✓ Branch 1 taken 698 times.
✗ Branch 2 not taken.
|
698 | _gnssNavInfo.addSatelliteNavData(satId, ephemeris); |
407 | 698 | } | |
408 | } | ||
409 | 736 | }; | |
410 | |||
411 |
2/2✓ Branch 0 taken 245 times.
✓ Branch 1 taken 982 times.
|
1227 | if (subFrameId == 1) // Third through tenth words of subframe 1 shall each contain 6 parity bits as their LSBs |
412 | { | ||
413 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 1 of 11), p. 79 | ||
414 | // IS-GPS-200M: 20.3.3.3 Subframe 1, p. 91ff | ||
415 | // IS-GPS-200M: Table 20-I. Subframe 1 Parameters, p. 96 | ||
416 | |||
417 | // T_GD, af2, af1, af0 shall be two's complement, with the sign bit (+ or -) occupying the MSB | ||
418 | |||
419 | 245 | w++; | |
420 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 3 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
421 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | [[maybe_unused]] auto WN = static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 20) & 0b1111111111); // 10 BITS - Transmission Week Number |
422 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto L2ChannelCodes = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 18) & 0b11); // 2 BITS |
423 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto uraIndex = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111); // 4 BITS |
424 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto svHealth = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 8) & 0b111111); // 6 BITS |
425 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto IODC = static_cast<uint16_t>(((sfrbx.dwrd.at(w) >> 6) & 0b11) << 8); // 2 MSBs - 10 BITS TOTAL |
426 | LOG_DATA("{}: [{}] WN {}, L2ChannelCodes {}, uraIndex {}, svHealth {}, IODC {}", nameId(), satId, WN, L2ChannelCodes, uraIndex, svHealth, std::bitset<10>(IODC)); | ||
427 | |||
428 | 245 | w++; | |
429 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 4 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
430 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto L2DataFlagPCode = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 29) & 0b1); // 1 BIT |
431 | LOG_DATA("{}: [{}] L2DataFlagPCode {}", nameId(), satId, L2DataFlagPCode); | ||
432 | |||
433 | 245 | w++; | |
434 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 5 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
435 | |||
436 | 245 | w++; | |
437 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 6 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
438 | |||
439 | 245 | w++; | |
440 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 7 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
441 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto T_GD = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 6) & 0b11111111); |
442 | LOG_DATA("{}: [{}] T_GD {}", nameId(), satId, T_GD); | ||
443 | |||
444 | 245 | w++; | |
445 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 8 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
446 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | IODC |= static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111); // 8 LSBs - 10 BITS TOTAL |
447 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto toc = static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 6) & 0b1111111111111111); // 16 LSBs |
448 | LOG_DATA("{}: [{}] IODC {} ({}), toc {}", nameId(), satId, IODC, std::bitset<10>(IODC), toc); | ||
449 | |||
450 | 245 | w++; | |
451 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 9 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
452 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto af2 = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111); // 8 BITS |
453 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto af1 = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 6) & 0b1111111111111111); // 16 BITS |
454 | LOG_DATA("{}: [{}] af2 {}, af1 {}", nameId(), satId, af2, af1); | ||
455 | |||
456 | 245 | w++; | |
457 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 10 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
458 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto af0 = math::interpretAs<int32_t, 22>(sfrbx.dwrd.at(w) >> 8); // 22 BITS |
459 | LOG_DATA("{}: [{}] af0 {}", nameId(), satId, af0); | ||
460 | |||
461 |
1/2✓ Branch 3 taken 245 times.
✗ Branch 4 not taken.
|
245 | InsTime insTimeToc(gpsWeekToW.gpsCycle, gpsWeekToW.gpsWeek, toc * std::pow(2, 4), GPST); |
462 | |||
463 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto& ephemerisBuilder = getEphemerisBuilder(satId, insTimeToc); |
464 | 245 | auto ephemeris = std::dynamic_pointer_cast<GPSEphemeris>(ephemerisBuilder.navData); | |
465 | 245 | ephemeris->toc = insTimeToc; | |
466 | |||
467 | 245 | ephemeris->L2ChannelCodes = L2ChannelCodes; | |
468 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | ephemeris->svAccuracy = gpsUraIdx2Val(uraIndex); |
469 | 245 | ephemeris->svHealth = svHealth; | |
470 | 245 | ephemeris->IODC = IODC; | |
471 | 245 | ephemeris->L2DataFlagPCode = L2DataFlagPCode; | |
472 | 245 | ephemeris->T_GD = T_GD * std::pow(2, -31); | |
473 | 245 | ephemeris->refTime = ephemeris->toc; | |
474 | 245 | ephemeris->a = { | |
475 | 245 | af0 * std::pow(2, -31), | |
476 | 245 | af1 * std::pow(2, -43), | |
477 | 245 | af2 * std::pow(2, -55), | |
478 | }; | ||
479 | LOG_DATA("{}: [{}] svAccuracy [{} m], svHealth [{}], IODC [{}], tgd [{:.3e} s]", nameId(), satId, | ||
480 | ephemeris->svAccuracy, ephemeris->svHealth, ephemeris->IODC, ephemeris->T_GD); | ||
481 | LOG_DATA("{}: [{}] toc [{}], a0 [{:.3e} s], a1 [{:.3e} s/s], a2 [{:.3e} s/s^2]", nameId(), satId, | ||
482 | ephemeris->toc.toYMDHMS(GPST), ephemeris->a[0], ephemeris->a[1], ephemeris->a[2]); | ||
483 | |||
484 |
1/2✓ Branch 2 taken 245 times.
✗ Branch 3 not taken.
|
245 | finishSubFrame(ephemeris, subFrameId, ephemerisBuilder.subframes); |
485 | 245 | } | |
486 |
2/2✓ Branch 0 taken 246 times.
✓ Branch 1 taken 736 times.
|
982 | else if (subFrameId == 2) // The third through tenth words of subframes 2 and 3 shall each contain six parity bits as their LSBs |
487 | { | ||
488 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 2 of 11), p. 80 | ||
489 | // IS-GPS-200M: 20.3.3.4 Subframes 2 and 3, p. 101ff | ||
490 | // IS-GPS-200M: Table 20-III. Ephemeris Parameters, p. 105 | ||
491 | |||
492 | // Crs, delta_n, M_0, Cuc, Cus shall be two's complement, with the sign bit (+ or -) occupying the MSB | ||
493 | |||
494 | 246 | w++; | |
495 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 3 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
496 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | auto IODE = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111); // 8 BITS |
497 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | auto Crs = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 6) & 0b1111111111111111); // 16 BITS |
498 | LOG_DATA("{}: [{}] IODE {}, Crs {}", nameId(), satId, IODE, Crs); | ||
499 | |||
500 | 246 | w++; | |
501 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 4 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
502 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | auto delta_n = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111111111); // 16 BITS |
503 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | auto M_0 = static_cast<int32_t>(((sfrbx.dwrd.at(w) >> 6) & 0b11111111) << 24); // 8 MSBs - 32 BITS TOTAL |
504 | LOG_DATA("{}: [{}] delta_n {}, M_0 {}", nameId(), satId, delta_n, std::bitset<32>(static_cast<uint32_t>(M_0))); | ||
505 | |||
506 | 246 | w++; | |
507 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 5 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
508 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | M_0 |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 6) & 0b111111111111111111111111); // 24 LSBs - 32 BITS TOTAL |
509 | LOG_DATA("{}: [{}] M_0 {} ({})", nameId(), satId, M_0, std::bitset<32>(static_cast<uint32_t>(M_0))); | ||
510 | |||
511 | 246 | w++; | |
512 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 6 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
513 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | auto Cuc = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111111111); // 16 BITS |
514 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | uint32_t e = ((sfrbx.dwrd.at(w) >> 6) & 0b11111111) << 24; // 8 MSBs - 32 BITS TOTAL |
515 | LOG_DATA("{}: [{}] Cuc {}, e {}", nameId(), satId, Cuc, std::bitset<32>(e)); | ||
516 | |||
517 | 246 | w++; | |
518 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 7 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
519 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | e |= (sfrbx.dwrd.at(w) >> 6) & 0b111111111111111111111111; // 24 LSBs - 32 BITS TOTAL |
520 | LOG_DATA("{}: [{}] e {} ({})", nameId(), satId, e, std::bitset<32>(e)); | ||
521 | |||
522 | 246 | w++; | |
523 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 8 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
524 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | auto Cus = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111111111); // 16 BITS |
525 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | uint32_t sqrt_A = ((sfrbx.dwrd.at(w) >> 6) & 0b11111111) << 24; // 8 MSBs - 32 BITS TOTAL |
526 | LOG_DATA("{}: [{}] Cus {}, sqrt_A {}", nameId(), satId, Cus, std::bitset<32>(sqrt_A)); | ||
527 | |||
528 | 246 | w++; | |
529 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 9 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
530 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | sqrt_A |= (sfrbx.dwrd.at(w) >> 6) & 0b111111111111111111111111; // 24 LSBs - 32 BITS TOTAL |
531 | LOG_DATA("{}: [{}] sqrt_A {} ({})", nameId(), satId, sqrt_A, std::bitset<32>(sqrt_A)); | ||
532 | |||
533 | 246 | w++; | |
534 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 10 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
535 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | auto toe = static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111111111); // 16 BITS |
536 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | auto fitInterval = static_cast<bool>((sfrbx.dwrd.at(w) >> 13) & 0b1); // 1 BIT |
537 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | [[maybe_unused]] auto AODO = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 8) & 0b11111); // 5 BITS |
538 | LOG_DATA("{}: [{}] toe {}, fitInterval {}, AODO {}", nameId(), satId, toe, fitInterval, AODO); | ||
539 | |||
540 |
1/2✓ Branch 3 taken 246 times.
✗ Branch 4 not taken.
|
246 | InsTime insTimeToe(gpsWeekToW.gpsCycle, gpsWeekToW.gpsWeek, toe * std::pow(2, 4), GPST); |
541 | |||
542 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | auto& ephemerisBuilder = getEphemerisBuilder(satId, insTimeToe); |
543 | 246 | auto ephemeris = std::dynamic_pointer_cast<GPSEphemeris>(ephemerisBuilder.navData); | |
544 | 246 | ephemeris->toe = insTimeToe; | |
545 | |||
546 | 246 | ephemeris->IODE = IODE; | |
547 | 246 | ephemeris->Crs = Crs * std::pow(2, -5); | |
548 | 246 | ephemeris->delta_n = semicircles2rad(delta_n * std::pow(2, -43)); | |
549 | 246 | ephemeris->M_0 = semicircles2rad(M_0 * std::pow(2, -31)); | |
550 | 246 | ephemeris->Cuc = Cuc * std::pow(2, -29); | |
551 | 246 | ephemeris->e = e * std::pow(2, -33); | |
552 | 246 | ephemeris->Cus = Cus * std::pow(2, -29); | |
553 | 246 | ephemeris->sqrt_A = sqrt_A * std::pow(2, -19); | |
554 |
1/2✓ Branch 3 taken 246 times.
✗ Branch 4 not taken.
|
246 | ephemeris->toe = InsTime(gpsWeekToW.gpsCycle, gpsWeekToW.gpsWeek, toe * std::pow(2, 4), GPST); |
555 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
|
246 | ephemeris->fitInterval = fitInterval ? 8.0 : 4.0; |
556 | // AODO | ||
557 | |||
558 | LOG_DATA("{}: [{}] IODE [{}], Crs [{:.3e} m], delta_n [{:.3e} rad/s], M_0 [{:.3e} rad], Cuc [{:.3e} rad]", nameId(), satId, | ||
559 | ephemeris->IODE, ephemeris->Crs, ephemeris->delta_n, ephemeris->M_0, ephemeris->Cuc); | ||
560 | LOG_DATA("{}: [{}] e [{:.3e}], Cus [{:.3e} rad], sqrt_A [{:.3e} m^(1/2)], toe [{}], fitInterval [{:.1f}]", nameId(), satId, | ||
561 | ephemeris->e, ephemeris->Cus, ephemeris->sqrt_A, ephemeris->toe.toGPSweekTow(GPST), ephemeris->fitInterval); | ||
562 | |||
563 |
1/2✓ Branch 2 taken 246 times.
✗ Branch 3 not taken.
|
246 | finishSubFrame(ephemeris, subFrameId, ephemerisBuilder.subframes); |
564 | 246 | } | |
565 |
2/2✓ Branch 0 taken 245 times.
✓ Branch 1 taken 491 times.
|
736 | else if (subFrameId == 3) // The third through tenth words of subframes 2 and 3 shall each contain six parity bits as their LSBs |
566 | { | ||
567 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 3 of 11), p. 81 | ||
568 | // IS-GPS-200M: 20.3.3.4 Subframes 2 and 3, p. 101ff | ||
569 | // IS-GPS-200M: Table 20-III. Ephemeris Parameters, p. 105 | ||
570 | |||
571 | // Cic, Omega_0, Cis, i_0, Crc, omega, Omega_dot, IDOT shall be two's complement, with the sign bit (+ or -) occupying the MSB | ||
572 | |||
573 | 245 | w++; | |
574 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 3 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
575 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto Cic = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111111111); // 16 BITS |
576 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto Omega_0 = static_cast<int32_t>(((sfrbx.dwrd.at(w) >> 6) & 0b11111111) << 24); // 8 MSBs - 32 BITS TOTAL |
577 | LOG_DATA("{}: [{}] Cic {}, Omega_0 {}", nameId(), satId, Cic, std::bitset<32>(static_cast<uint32_t>(Omega_0))); | ||
578 | |||
579 | 245 | w++; | |
580 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 4 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
581 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | Omega_0 |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 6) & 0b111111111111111111111111); // 24 LSBs - 32 BITS TOTAL |
582 | LOG_DATA("{}: [{}] Omega_0 {} ({})", nameId(), satId, Omega_0, std::bitset<32>(static_cast<uint32_t>(Omega_0))); | ||
583 | |||
584 | 245 | w++; | |
585 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 5 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
586 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto Cis = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111111111); // 16 BITS |
587 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto i_0 = static_cast<int32_t>(((sfrbx.dwrd.at(w) >> 6) & 0b11111111) << 24); // 8 MSBs - 32 BITS TOTAL |
588 | LOG_DATA("{}: [{}] Cis {}, i_0 {}", nameId(), satId, Cis, std::bitset<32>(static_cast<uint32_t>(i_0))); | ||
589 | |||
590 | 245 | w++; | |
591 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 6 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
592 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | i_0 |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 6) & 0b111111111111111111111111); // 24 LSBs - 32 BITS TOTAL |
593 | LOG_DATA("{}: [{}] i_0 {} ({})", nameId(), satId, i_0, std::bitset<32>(static_cast<uint32_t>(i_0))); | ||
594 | |||
595 | 245 | w++; | |
596 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 7 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
597 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto Crc = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111111111); // 16 BITS |
598 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto omega = static_cast<int32_t>(((sfrbx.dwrd.at(w) >> 6) & 0b11111111) << 24); // 8 MSBs - 32 BITS TOTAL |
599 | LOG_DATA("{}: [{}] Crc {}, omega {}", nameId(), satId, Crc, std::bitset<32>(static_cast<uint32_t>(omega))); | ||
600 | |||
601 | 245 | w++; | |
602 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 8 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
603 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | omega |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 6) & 0b111111111111111111111111); // 24 LSBs - 32 BITS TOTAL |
604 | LOG_DATA("{}: [{}] omega {} ({})", nameId(), satId, omega, std::bitset<32>(static_cast<uint32_t>(omega))); | ||
605 | |||
606 | 245 | w++; | |
607 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 9 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
608 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto Omega_dot = math::interpretAs<int32_t, 24>(sfrbx.dwrd.at(w) >> 6); // 24 BITS |
609 | LOG_DATA("{}: [{}] Omega_dot {} ({})", nameId(), satId, Omega_dot, std::bitset<32>(static_cast<uint32_t>(Omega_dot))); | ||
610 | |||
611 | 245 | w++; | |
612 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 10 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
613 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto IODE = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111); // 8 BITS |
614 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto i_dot = math::interpretAs<int16_t, 14>(sfrbx.dwrd.at(w) >> 8); // 14 BITS |
615 | LOG_DATA("{}: [{}] IODE {}, i_dot {} ({})", nameId(), satId, IODE, i_dot, std::bitset<16>(static_cast<uint16_t>(i_dot))); | ||
616 | |||
617 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | auto ephemerisBuilder = getEphemerisBuilder(satId, IODE); |
618 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 245 times.
|
245 | if (!ephemerisBuilder.has_value()) |
619 | { | ||
620 | LOG_DATA("{}: [{}] Could not find Ephemeris builder for IODE {}", nameId(), satId, IODE); | ||
621 | ✗ | return; | |
622 | } | ||
623 | 245 | auto ephemeris = std::dynamic_pointer_cast<GPSEphemeris>(ephemerisBuilder->get().navData); | |
624 | |||
625 | 245 | ephemeris->Cic = Cic * std::pow(2, -29); | |
626 | 245 | ephemeris->Omega_0 = semicircles2rad(Omega_0 * std::pow(2, -31)); | |
627 | 245 | ephemeris->Cis = Cis * std::pow(2, -29); | |
628 | 245 | ephemeris->i_0 = semicircles2rad(i_0 * std::pow(2, -31)); | |
629 | 245 | ephemeris->Crc = Crc * std::pow(2, -5); | |
630 | 245 | ephemeris->omega = semicircles2rad(omega * std::pow(2, -31)); | |
631 | 245 | ephemeris->Omega_dot = semicircles2rad(Omega_dot * std::pow(2, -43)); | |
632 | 245 | ephemeris->IODE = IODE; | |
633 | 245 | ephemeris->i_dot = semicircles2rad(i_dot * std::pow(2, -43)); | |
634 | |||
635 | LOG_DATA("{}: [{}] Cic [{:.3e} rad], Omega_0 [{:.3e} rad], Cis [{:.3e} rad], i_0 [{:.3e} rad], Crc [{:.3e} m]", nameId(), satId, | ||
636 | ephemeris->Cic, ephemeris->Omega_0, ephemeris->Cis, ephemeris->i_0, ephemeris->Crc); | ||
637 | LOG_DATA("{}: [{}] omega [{:.3e} rad], Omega_dot [{:.3e} rad/s], IODE [{}], i_dot [{:.3e} rad/s]", nameId(), satId, | ||
638 | ephemeris->omega, ephemeris->Omega_dot, ephemeris->IODE, ephemeris->i_dot); | ||
639 | |||
640 |
1/2✓ Branch 4 taken 245 times.
✗ Branch 5 not taken.
|
245 | finishSubFrame(ephemeris, subFrameId, ephemerisBuilder->get().subframes); |
641 | 245 | } | |
642 |
2/2✓ Branch 0 taken 237 times.
✓ Branch 1 taken 254 times.
|
491 | else if (subFrameId == 4) // Words three through ten of each page contain six parity bits as their LSBs |
643 | { | ||
644 | // Page | SV ID | Description | ||
645 | // ------------------------ | ------------------------------ | ----------- | ||
646 | // 1, 6, 11, 16, 21: | 57 | Reserved | ||
647 | // 2, 3, 4, 5, 7, 8, 9, 10: | 25, 26, 27, 28, 29, 30, 31, 32 | almanac data for SV 25 through 32 respectively | ||
648 | // 12, 19, 20, 22, 23, 24: | 62, 58, 59, 60, 61, 62 | Reserved | ||
649 | // 13: | 52 | NMCT | ||
650 | // 14, 15: | 53, 54 | Reserved for system use | ||
651 | // 17: | 55 | Special messages | ||
652 | // 18: | 56 | Ionospheric and UTC data | ||
653 | // 25: | 63 | A-S flags/SV configurations for 32 SVs, plus SV health for SV 25 through 32 | ||
654 | // | ||
655 | // IS-GPS-200M: Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, p. 114 | ||
656 | // IS-GPS-200M: 20.3.3.5 Subframes 4 and 5, p. 112ff | ||
657 | |||
658 | 237 | w++; | |
659 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 3 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
660 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | [[maybe_unused]] auto dataId = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 28) & 0b11); // 2 BITS |
661 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto svId = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 22) & 0b111111); // 6 BITS |
662 | LOG_DATA("{}: [{}] dataId {}, svId {}", nameId(), satId, dataId, svId); | ||
663 | |||
664 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 229 times.
|
237 | if (svId == 56) // IS-GPS-200M: Figure 20-1. Data Format (sheet 8 of 11), p. 86 - for page 18 |
665 | { | ||
666 | // IS-GPS-200M: 20.3.3.5.1.6 Coordinated Universal Time (UTC) Parameters, p. 121 | ||
667 | // IS-GPS-200M: Table 20-IX. UTC Parameters, p. 122 | ||
668 | |||
669 | // IS-GPS-200M: 20.3.3.5.1.7 Ionospheric Data, p. 121 | ||
670 | // IS-GPS-200M: Table 20-X. Ionospheric Parameters, p. 123 | ||
671 | |||
672 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto alpha0 = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 14) & 0b11111111); // 8 BITS |
673 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto alpha1 = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 6) & 0b11111111); // 8 BITS |
674 | LOG_DATA("{}: [{}] alpha0 {}, alpha1 {}", nameId(), satId, alpha0, alpha1); | ||
675 | |||
676 | 8 | w++; | |
677 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 4 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
678 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto alpha2 = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111); // 8 BITS |
679 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto alpha3 = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 14) & 0b11111111); // 8 BITS |
680 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto beta0 = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 6) & 0b11111111); // 8 BITS |
681 | LOG_DATA("{}: [{}] alpha2 {}, alpha3 {}, beta0 {}", nameId(), satId, alpha2, alpha3, beta0); | ||
682 | |||
683 | 8 | w++; | |
684 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 5 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
685 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto beta1 = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111); // 8 BITS |
686 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto beta2 = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 14) & 0b11111111); // 8 BITS |
687 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto beta3 = static_cast<int8_t>((sfrbx.dwrd.at(w) >> 6) & 0b11111111); // 8 BITS |
688 | LOG_DATA("{}: [{}] beta1 {}, beta2 {}, beta3 {}", nameId(), satId, beta1, beta2, beta3); | ||
689 | |||
690 | 8 | w++; | |
691 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 6 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
692 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto A1 = math::interpretAs<int32_t, 24>(sfrbx.dwrd.at(w) >> 6); // 24 BITS |
693 | LOG_DATA("{}: [{}] A1 {}", nameId(), satId, A1); | ||
694 | |||
695 | 8 | w++; | |
696 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 7 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
697 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto A0 = static_cast<int32_t>(((sfrbx.dwrd.at(w) >> 6) & 0b111111111111111111111111) << 8); // 24 MSBs - 32 BITS TOTAL |
698 | LOG_DATA("{}: [{}] A0 {}", nameId(), satId, std::bitset<32>(static_cast<uint32_t>(A0))); | ||
699 | |||
700 | 8 | w++; | |
701 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 8 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
702 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | A0 |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111); // 8 LSBs - 32 BITS TOTAL |
703 | LOG_DATA("{}: [{}] A0 {} ({})", nameId(), satId, A0, std::bitset<32>(static_cast<uint32_t>(A0))); | ||
704 | |||
705 | 8 | w++; | |
706 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 9 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
707 | |||
708 | 8 | w++; | |
709 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 10 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
710 | |||
711 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | std::unique_lock guard(outputPins.at(OUTPUT_PORT_INDEX_GNSS_NAV_INFO).dataAccessMutex, std::defer_lock); |
712 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
|
8 | if (!_postProcessingLock.has_value()) |
713 | { | ||
714 | ✗ | guard.lock(); | |
715 | } | ||
716 |
3/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 7 times.
|
8 | if (!_gnssNavInfo.ionosphericCorrections.contains(satId.satSys, IonosphericCorrections::Alpha)) |
717 | { | ||
718 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
2 | if (auto ephemerisBuilder = getLastEphemerisBuilder(satId); |
719 | 1 | ephemerisBuilder.has_value()) | |
720 | { | ||
721 | 1 | auto ephemeris = std::dynamic_pointer_cast<GPSEphemeris>(ephemerisBuilder->get().navData); | |
722 |
4/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
|
1 | LOG_DEBUG("{}: [{}] Received Ionospheric and Time system corrections [{}]", nameId(), satId.satSys, ephemeris->refTime.toYMDHMS(GPST)); |
723 | 1 | } | |
724 | else | ||
725 | { | ||
726 | ✗ | LOG_DEBUG("{}: [{}] Received Ionospheric and Time system corrections", nameId(), satId.satSys); | |
727 | } | ||
728 | } | ||
729 | |||
730 | ✗ | _gnssNavInfo.ionosphericCorrections.insert(satId.satSys, IonosphericCorrections::Alpha, | |
731 | { | ||
732 | 8 | alpha0 * std::pow(2, -30) /* [s] */, | |
733 | 8 | alpha1 * std::pow(2, -27) /* [s/semi-circle] */, | |
734 | 8 | alpha2 * std::pow(2, -24) /* [s/semi-circle^2] */, | |
735 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | alpha3 * std::pow(2, -24) /* [s/semi-circle^3] */, |
736 | }); | ||
737 | ✗ | _gnssNavInfo.ionosphericCorrections.insert(satId.satSys, IonosphericCorrections::Beta, | |
738 | { | ||
739 | 8 | beta0 * std::pow(2, 11) /* [s] */, | |
740 | 8 | beta1 * std::pow(2, 14) /* [s/semi-circle] */, | |
741 | 8 | beta2 * std::pow(2, 16) /* [s/semi-circle^2] */, | |
742 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | beta3 * std::pow(2, 16) /* [s/semi-circle^3] */, |
743 | }); | ||
744 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
|
8 | _gnssNavInfo.timeSysCorr[{ satId.satSys.getTimeSystem(), UTC }] = GnssNavInfo::TimeSystemCorrections{ |
745 | 8 | .a0 = A0 * std::pow(2, -30), | |
746 | 8 | .a1 = A1 * std::pow(2, -50), | |
747 | }; | ||
748 | 8 | } | |
749 | else | ||
750 | { | ||
751 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 6 of 11), p. 84 - for pages 1, 6, 11, 16 and 21 | ||
752 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 7 of 11), p. 85 - for pages 12, 19, 20, 22, 23 and 24 | ||
753 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 9 of 11), p. 87 - for page 25 | ||
754 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 10 of 11), p. 88 - for page 13 | ||
755 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 11 of 11), p. 89 - for pages 14, 15 and 17 | ||
756 | |||
757 | 229 | w++; | |
758 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 4 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
759 | 229 | w++; | |
760 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 5 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
761 | 229 | w++; | |
762 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 6 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
763 | 229 | w++; | |
764 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 7 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
765 | 229 | w++; | |
766 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 8 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
767 | 229 | w++; | |
768 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 9 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
769 | 229 | w++; | |
770 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 10 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
771 | } | ||
772 | } | ||
773 |
1/2✓ Branch 0 taken 254 times.
✗ Branch 1 not taken.
|
254 | else if (subFrameId == 5) // Words three through ten of each page contain six parity bits as their LSBs |
774 | { | ||
775 | // Page description | ||
776 | // 1 through 24: almanac data for SV 1 through 24 | ||
777 | // 25: SV health data for SV 1 through 24, the almanac reference time, the almanac reference week number | ||
778 | // | ||
779 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 4 of 11), p. 82 - for page 1 through 24 | ||
780 | // IS-GPS-200M: Figure 20-1. Data Format (sheet 5 of 11), p. 83 - for page 25 | ||
781 | // IS-GPS-200M: 20.3.3.5 Subframes 4 and 5, p. 112ff | ||
782 | |||
783 | 254 | w++; | |
784 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 3 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
785 | 254 | w++; | |
786 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 4 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
787 | 254 | w++; | |
788 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 5 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
789 | 254 | w++; | |
790 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 6 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
791 | 254 | w++; | |
792 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 7 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
793 | 254 | w++; | |
794 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 8 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
795 | 254 | w++; | |
796 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 9 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
797 | 254 | w++; | |
798 | LOG_DATA("{}: [{}] word {:2}: {} {}", nameId(), satId, w + 1 /* 10 */, std::bitset<2>(sfrbx.dwrd.at(w) >> 30), std::bitset<30>(sfrbx.dwrd.at(w))); | ||
799 | } | ||
800 | } | ||
801 | |||
802 | 4211 | void NAV::UbloxGnssOrbitCollector::decryptGalileo(const SatId& satId, const ubx::UbxRxmSfrbx& sfrbx, const InsTime& insTime) | |
803 | { | ||
804 | // u-blox 8 / u-blox M8: Receiver description - Including protocol specification, ch. 10.5, p. 32f | ||
805 | // > The Galileo E1OS and E5b signals both transmit the I/NAV message but in different configurations. | ||
806 | // > For Galileo E1OS signals, each reported subframe contains a pair of I/NAV pages as described in | ||
807 | // > the Galileo ICD. | ||
808 | // > Galileo pages can either be "Nominal" or "Alert" pages. For Nominal pages the eight words are | ||
809 | // > arranged as follows: | ||
810 | // > | ||
811 | // > MSB LSB | ||
812 | // > 1: Even/Odd (1 bit) Page type (1 bit) Word type (6 bits) Data (122 - 99) (24 bits) | ||
813 | // > 2: Data (98 - 67) (32 bits) | ||
814 | // > 3: Data (66 - 35) (32 bits) | ||
815 | // > 4: Data (34 - 17) (18 bits) Tail (6 bits) Pad (8 bits) | ||
816 | // > 5: Even/Odd (1 bit) Page type (1 bit) Data (16 - 1) (16 bits) Reserved 1 (40 - 27) (14 bits) | ||
817 | // > 6: Reserved 2 (26 - 1) (26 bits) SAR (22 - 17) (6 bits) | ||
818 | // > 7: SAR (16 - 1) (16 bits) Spare (2 bits) CRC (24 - 11) (14 bits) | ||
819 | // > 8: CRC (10 - 1) (10 bits) Reserved 2 (8 bits) Tail (6 bits) Pad (8 bits) | ||
820 | // > | ||
821 | // > Alert pages are reported in very similar manner, but the page type bits will have value 1 and the | ||
822 | // > structure of the eight words will be slightly different (as indicated by the Galileo ICD). | ||
823 | |||
824 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4211 times.
|
4211 | if (sfrbx.numWords != 8) |
825 | { | ||
826 | ✗ | LOG_ERROR("{}: [{}] Received {} instead of 8 words", nameId(), satId, sfrbx.numWords); | |
827 | 695 | return; | |
828 | } | ||
829 | |||
830 | 4211 | size_t w = 0; // Word counter | |
831 | |||
832 |
1/2✓ Branch 1 taken 4211 times.
✗ Branch 2 not taken.
|
4211 | auto even = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 31) & 0b1); |
833 |
1/2✓ Branch 1 taken 4211 times.
✗ Branch 2 not taken.
|
4211 | auto pageTypeEven = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 30) & 0b1); |
834 |
1/2✓ Branch 1 taken 4211 times.
✗ Branch 2 not taken.
|
4211 | auto odd = static_cast<uint8_t>((sfrbx.dwrd.at(4) >> 31) & 0b1); |
835 |
1/2✓ Branch 1 taken 4211 times.
✗ Branch 2 not taken.
|
4211 | auto pageTypeOdd = static_cast<uint8_t>((sfrbx.dwrd.at(4) >> 30) & 0b1); |
836 |
1/2✓ Branch 1 taken 4211 times.
✗ Branch 2 not taken.
|
4211 | auto wordType = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 24) & 0b111111); |
837 | LOG_DATA("{}: [{}] wordType: {:2}, even {} ({} pageType), odd {} ({} pageType)", nameId(), satId, wordType, even, pageTypeEven, odd, pageTypeOdd); | ||
838 | |||
839 |
2/4✓ Branch 0 taken 4211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4211 times.
✗ Branch 3 not taken.
|
4211 | if (even != 0 || pageTypeEven == 1 |
840 |
4/4✓ Branch 0 taken 3814 times.
✓ Branch 1 taken 397 times.
✓ Branch 2 taken 237 times.
✓ Branch 3 taken 3577 times.
|
4211 | || odd != 1 || pageTypeOdd == 1) |
841 | { | ||
842 | LOG_DATA("{}: [{}] Ignoring message, because one of the page types is alert page", nameId(), satId); | ||
843 | 634 | return; | |
844 | } | ||
845 | |||
846 |
1/2✓ Branch 2 taken 3577 times.
✗ Branch 3 not taken.
|
3577 | auto gpsWeekToW = insTime.toGPSweekTow(GST); |
847 | |||
848 | 1103 | auto finishWord = [&]<size_t N>(const std::shared_ptr<SatNavData>& ephemeris, size_t wordType, std::bitset<N>& subframesFound) { | |
849 |
2/4✓ Branch 0 taken 1103 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1103 times.
✗ Branch 3 not taken.
|
1103 | if (1 <= wordType && wordType <= 5) |
850 | { | ||
851 | 1103 | subframesFound.set(wordType - 1); | |
852 | |||
853 | LOG_DATA("{}: [{}] subframesFound: {}", nameId(), satId, subframesFound); | ||
854 |
2/2✓ Branch 1 taken 989 times.
✓ Branch 2 taken 114 times.
|
1103 | if (subframesFound.count() == 5) |
855 | { | ||
856 | LOG_DATA("{}: [{}] [{}] All words found. Updating gnnsNavInfo", nameId(), satId, ephemeris->refTime.toYMDHMS(GPST)); | ||
857 |
3/4✓ Branch 2 taken 989 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 978 times.
|
989 | if (!_gnssNavInfo.searchNavigationData(satId, ephemeris->refTime)) |
858 | { | ||
859 |
4/8✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 11 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 11 times.
✗ Branch 14 not taken.
|
11 | LOG_DEBUG("{}: Adding new ephemeris data [{}] [{}]", nameId(), satId, ephemeris->refTime.toYMDHMS(GPST)); |
860 | } | ||
861 |
1/2✓ Branch 1 taken 989 times.
✗ Branch 2 not taken.
|
989 | std::unique_lock guard(outputPins.at(OUTPUT_PORT_INDEX_GNSS_NAV_INFO).dataAccessMutex, std::defer_lock); |
862 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 989 times.
|
989 | if (!_postProcessingLock.has_value()) |
863 | { | ||
864 | ✗ | guard.lock(); | |
865 | } | ||
866 | 989 | _gnssNavInfo.satelliteSystems |= satId.satSys; | |
867 |
1/2✓ Branch 1 taken 989 times.
✗ Branch 2 not taken.
|
989 | _gnssNavInfo.addSatelliteNavData(satId, ephemeris); |
868 | 989 | } | |
869 | } | ||
870 | 1103 | }; | |
871 | |||
872 |
2/2✓ Branch 0 taken 227 times.
✓ Branch 1 taken 3350 times.
|
3577 | if (wordType == 1) // Ephemeris (1/4) |
873 | { | ||
874 | // Galileo-OS-SIS-ICD-v2.0: ch. 4.3.5, Table 40 Bits Allocation for I/NAV Word Type 1, p. 37 | ||
875 | // | ||
876 | // Even/Odd PageType WordType IODnav toe M_0 e sqrt_A Tail Pad Even/Odd PageType sqrt_A Reserved Reserved 1 | ||
877 | // 1 1 6 10 14 32 32 18 6 8 1 1 14 2 14 | ||
878 | // └───────────────────┬───────────────────┘ │ │ └───────┬───────┘ └───────────────────────┬──────────────────────┘ | ||
879 | // Ublox 1 2 3 4 5 | ||
880 | |||
881 | // Galileo-OS-SIS-ICD-v2.0: ch. 5.1.1, Table 60 Ephemeris Parameters, p. 43f | ||
882 | // > M_0 shall be two's complement, with the sign bit (+ or -) occupying the MSB | ||
883 | |||
884 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 1 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
885 |
1/2✓ Branch 1 taken 227 times.
✗ Branch 2 not taken.
|
227 | auto IODnav = static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111); |
886 |
1/2✓ Branch 1 taken 227 times.
✗ Branch 2 not taken.
|
227 | auto toe = static_cast<uint16_t>(sfrbx.dwrd.at(w) & 0b11111111111111); |
887 | LOG_DATA("{}: [{}] IODnav {}, toe {}", nameId(), satId, IODnav, toe); | ||
888 | |||
889 | 227 | w++; | |
890 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 2 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
891 |
1/2✓ Branch 1 taken 227 times.
✗ Branch 2 not taken.
|
227 | auto M_0 = static_cast<int32_t>(sfrbx.dwrd.at(w)); |
892 | LOG_DATA("{}: [{}] M_0 {}", nameId(), satId, M_0); | ||
893 | |||
894 | 227 | w++; | |
895 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 3 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
896 |
1/2✓ Branch 1 taken 227 times.
✗ Branch 2 not taken.
|
227 | uint32_t e = sfrbx.dwrd.at(w); |
897 | LOG_DATA("{}: [{}] e {}", nameId(), satId, e); | ||
898 | |||
899 | 227 | w++; | |
900 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 4 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
901 |
1/2✓ Branch 1 taken 227 times.
✗ Branch 2 not taken.
|
227 | uint32_t sqrt_A = ((sfrbx.dwrd.at(w) >> 14) & 0b111111111111111111) << 14; |
902 | LOG_DATA("{}: [{}] sqrt_A {}", nameId(), satId, std::bitset<32>(sqrt_A)); | ||
903 | |||
904 | 227 | w++; | |
905 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 5 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
906 |
1/2✓ Branch 1 taken 227 times.
✗ Branch 2 not taken.
|
227 | sqrt_A |= (sfrbx.dwrd.at(w) >> 16) & 0b11111111111111; |
907 | LOG_DATA("{}: [{}] sqrt_A {} ({})", nameId(), satId, sqrt_A, std::bitset<32>(sqrt_A)); | ||
908 | |||
909 |
1/2✓ Branch 2 taken 227 times.
✗ Branch 3 not taken.
|
227 | InsTime insTimeToe(gpsWeekToW.gpsCycle, gpsWeekToW.gpsWeek, toe * 60.0, GST); |
910 | |||
911 |
1/2✓ Branch 1 taken 227 times.
✗ Branch 2 not taken.
|
227 | auto& ephemerisBuilder = getEphemerisBuilder(satId, insTimeToe, IODnav); |
912 | 227 | auto ephemeris = std::dynamic_pointer_cast<GalileoEphemeris>(ephemerisBuilder.navData); | |
913 | 227 | ephemeris->toe = insTimeToe; | |
914 | |||
915 | 227 | ephemeris->IODnav = IODnav; | |
916 | 227 | ephemeris->M_0 = semicircles2rad(M_0 * std::pow(2.0, -31)); | |
917 | 227 | ephemeris->e = e * std::pow(2.0, -33); | |
918 | 227 | ephemeris->sqrt_A = sqrt_A * std::pow(2.0, -19); | |
919 | |||
920 | LOG_DATA("{}: [{}] IODnav [{}], toe [{}], M_0 [{:.3e} rad], e [{:.3e}], sqrt_A [{:.3e} m^(1/2)]", nameId(), satId, | ||
921 | ephemeris->IODnav, ephemeris->toe.toYMDHMS(GPST), ephemeris->M_0, ephemeris->e, ephemeris->sqrt_A); | ||
922 | |||
923 |
1/2✓ Branch 2 taken 227 times.
✗ Branch 3 not taken.
|
227 | finishWord(ephemeris, wordType, ephemerisBuilder.subframes); |
924 | 227 | } | |
925 |
2/2✓ Branch 0 taken 236 times.
✓ Branch 1 taken 3114 times.
|
3350 | else if (wordType == 2) // Ephemeris (2/4) |
926 | { | ||
927 | // Galileo-OS-SIS-ICD-v2.0: ch. 4.3.5, Table 41 Bits Allocation for I/NAV Word Type 2, p. 37 | ||
928 | // | ||
929 | // Even/Odd PageType WordType IODnav Omega_0 Omega_0 i_0 i_0 omega omega Tail Pad Even/Odd PageType i_dot Reserved Reserved 1 | ||
930 | // 1 1 6 10 14 18 14 18 14 18 6 8 1 1 14 2 14 | ||
931 | // └──────────────────────┬────────────────────┘ └────┬─────┘ └────┬───┘ └───────┬────────┘ └──────────────────────┬──────────────────────┘ | ||
932 | // Ublox 1 2 3 4 5 | ||
933 | |||
934 | // Galileo-OS-SIS-ICD-v2.0: ch. 5.1.1, Table 60 Ephemeris Parameters, p. 43f | ||
935 | // > Omega_0, i_0, omega, i_dot shall be two's complement, with the sign bit (+ or -) occupying the MSB | ||
936 | |||
937 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 1 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
938 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto IODnav = static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111); |
939 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto Omega_0 = static_cast<int32_t>((sfrbx.dwrd.at(w) & 0b11111111111111) << 18); |
940 | LOG_DATA("{}: [{}] IODnav {}, Omega_0 {}", nameId(), satId, IODnav, std::bitset<32>(static_cast<uint32_t>(Omega_0))); | ||
941 | |||
942 | 236 | w++; | |
943 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 2 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
944 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | Omega_0 |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 14) & 0b111111111111111111); |
945 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto i_0 = static_cast<int32_t>((sfrbx.dwrd.at(w) & 0b11111111111111) << 18); |
946 | LOG_DATA("{}: [{}] Omega_0 {} ({}), i_0 {}", nameId(), satId, Omega_0, std::bitset<32>(static_cast<uint32_t>(Omega_0)), std::bitset<32>(static_cast<uint32_t>(i_0))); | ||
947 | |||
948 | 236 | w++; | |
949 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 3 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
950 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | i_0 |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 14) & 0b111111111111111111); |
951 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto omega = static_cast<int32_t>((sfrbx.dwrd.at(w) & 0b11111111111111) << 18); |
952 | LOG_DATA("{}: [{}] i_0 {} ({}), omega {}", nameId(), satId, i_0, std::bitset<32>(static_cast<uint32_t>(i_0)), std::bitset<32>(static_cast<uint32_t>(omega))); | ||
953 | |||
954 | 236 | w++; | |
955 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 4 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
956 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | omega |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 14) & 0b111111111111111111); |
957 | LOG_DATA("{}: [{}] omega {} ({})", nameId(), satId, omega, std::bitset<32>(static_cast<uint32_t>(omega))); | ||
958 | |||
959 | 236 | w++; | |
960 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 5 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
961 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto i_dot = math::interpretAs<int16_t, 14>(sfrbx.dwrd.at(w) >> 16); |
962 | LOG_DATA("{}: [{}] i_dot {} ({})", nameId(), satId, i_dot, std::bitset<16>(static_cast<uint16_t>(i_dot))); | ||
963 | |||
964 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto ephemerisBuilder = getEphemerisBuilder(satId, IODnav); |
965 |
2/2✓ Branch 1 taken 27 times.
✓ Branch 2 taken 209 times.
|
236 | if (!ephemerisBuilder.has_value()) |
966 | { | ||
967 | LOG_DATA("{}: [{}] Could not find Ephemeris builder for IODnav {}", nameId(), satId, IODnav); | ||
968 | 27 | return; | |
969 | } | ||
970 | 209 | auto ephemeris = std::dynamic_pointer_cast<GalileoEphemeris>(ephemerisBuilder->get().navData); | |
971 | |||
972 | 209 | ephemeris->Omega_0 = semicircles2rad(Omega_0 * std::pow(2.0, -31)); | |
973 | 209 | ephemeris->i_0 = semicircles2rad(i_0 * std::pow(2.0, -31)); | |
974 | 209 | ephemeris->omega = semicircles2rad(omega * std::pow(2.0, -31)); | |
975 | 209 | ephemeris->i_dot = semicircles2rad(i_dot * std::pow(2.0, -43)); | |
976 | |||
977 | LOG_DATA("{}: [{}] IODnav [{}], Omega_0 [{} rad], i_0 [{:.3e} rad], omega [{:.3e} rad], i_dot [{:.3e} rad/s]", nameId(), satId, | ||
978 | ephemeris->IODnav, ephemeris->Omega_0, ephemeris->i_0, ephemeris->omega, ephemeris->i_dot); | ||
979 | |||
980 |
1/2✓ Branch 4 taken 209 times.
✗ Branch 5 not taken.
|
209 | finishWord(ephemeris, wordType, ephemerisBuilder->get().subframes); |
981 | 209 | } | |
982 |
2/2✓ Branch 0 taken 228 times.
✓ Branch 1 taken 2886 times.
|
3114 | else if (wordType == 3) // Ephemeris (3/4) and SISA |
983 | { | ||
984 | // Galileo-OS-SIS-ICD-v2.0: ch. 4.3.5, Table 42 Bits Allocation for I/NAV Word Type 3, p. 38 | ||
985 | // | ||
986 | // Even/Odd PageType WordType IODnav Omega_dot Omega_dot delta_n Cuc Cuc Cus Crc Crc Crs Tail Pad Even/Odd PageType Crs SISA(E1,E5b) Reserved 1 | ||
987 | // 1 1 6 10 14 10 16 6 10 16 6 10 8 6 8 1 1 8 8 14 | ||
988 | // └───────────────────────┬─────────────────────┘ └──────────┬──────────┘ └─────┬─────┘ └────────┬────────┘ └───────────────────────┬───────────────────────┘ | ||
989 | // Ublox 1 2 3 4 5 | ||
990 | |||
991 | // Galileo-OS-SIS-ICD-v2.0: ch. 5.1.1, Table 60 Ephemeris Parameters, p. 43f | ||
992 | // > Omega_dot, delta_n, Cuc, Cus, Crc, Crs shall be two's complement, with the sign bit (+ or -) occupying the MSB | ||
993 | |||
994 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 1 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
995 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | auto IODnav = static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111); |
996 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | auto Omega_dot = static_cast<int32_t>((sfrbx.dwrd.at(w) & 0b11111111111111) << 10); |
997 | LOG_DATA("{}: [{}] IODnav {}, Omega_dot {}", nameId(), satId, IODnav, std::bitset<32>(static_cast<uint32_t>(Omega_dot))); | ||
998 | |||
999 | 228 | w++; | |
1000 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 2 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1001 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | Omega_dot |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 22) & 0b1111111111); |
1002 | 228 | Omega_dot = math::interpretAs<int32_t, 24>(Omega_dot); | |
1003 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | auto delta_n = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 6) & 0b1111111111111111); |
1004 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | auto Cuc = static_cast<int16_t>((sfrbx.dwrd.at(w) & 0b111111) << 10); |
1005 | LOG_DATA("{}: [{}] Omega_dot {} ({}), delta_n {}, Cuc {}", nameId(), satId, | ||
1006 | Omega_dot, std::bitset<32>(static_cast<uint32_t>(Omega_dot)), delta_n, std::bitset<16>(static_cast<uint16_t>(Cuc))); | ||
1007 | |||
1008 | 228 | w++; | |
1009 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 3 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1010 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | Cuc |= static_cast<int16_t>((sfrbx.dwrd.at(w) >> 22) & 0b1111111111); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) |
1011 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | auto Cus = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 6) & 0b1111111111111111); |
1012 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | auto Crc = static_cast<int16_t>((sfrbx.dwrd.at(w) & 0b111111) << 10); |
1013 | LOG_DATA("{}: [{}] Cuc {} ({}), Cus {}, Crc {}", nameId(), satId, Cuc, std::bitset<16>(static_cast<uint16_t>(Cuc)), Cus, std::bitset<16>(static_cast<uint16_t>(Crc))); | ||
1014 | |||
1015 | 228 | w++; | |
1016 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 4 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1017 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | Crc |= static_cast<int16_t>((sfrbx.dwrd.at(w) >> 22) & 0b1111111111); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) |
1018 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | auto Crs = static_cast<int16_t>(((sfrbx.dwrd.at(w) >> 14) & 0b11111111) << 8); |
1019 | LOG_DATA("{}: [{}] Crc {} ({}), Crs {}", nameId(), satId, Crc, std::bitset<16>(static_cast<uint16_t>(Crc)), std::bitset<16>(static_cast<uint16_t>(Crs))); | ||
1020 | |||
1021 | 228 | w++; | |
1022 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 5 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1023 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | Crs |= static_cast<int16_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) |
1024 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | auto SISA = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 14) & 0b11111111); |
1025 | LOG_DATA("{}: [{}] Crs {} ({}), SISA {}", nameId(), satId, Crs, std::bitset<16>(static_cast<uint16_t>(Crs)), SISA); | ||
1026 | |||
1027 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
228 | auto ephemerisBuilder = getEphemerisBuilder(satId, IODnav); |
1028 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 225 times.
|
228 | if (!ephemerisBuilder.has_value()) |
1029 | { | ||
1030 | LOG_DATA("{}: [{}] Could not find Ephemeris builder for IODnav {}", nameId(), satId, IODnav); | ||
1031 | 3 | return; | |
1032 | } | ||
1033 | 225 | auto ephemeris = std::dynamic_pointer_cast<GalileoEphemeris>(ephemerisBuilder->get().navData); | |
1034 | |||
1035 | 225 | ephemeris->Omega_dot = semicircles2rad(Omega_dot * std::pow(2.0, -43)); | |
1036 | 225 | ephemeris->delta_n = semicircles2rad(delta_n * std::pow(2.0, -43)); | |
1037 | 225 | ephemeris->Cuc = Cuc * std::pow(2.0, -29); | |
1038 | 225 | ephemeris->Cus = Cus * std::pow(2.0, -29); | |
1039 | 225 | ephemeris->Crc = Crc * std::pow(2.0, -5); | |
1040 | 225 | ephemeris->Crs = Crs * std::pow(2.0, -5); | |
1041 |
1/2✓ Branch 1 taken 225 times.
✗ Branch 2 not taken.
|
225 | ephemeris->signalAccuracy = galSisaIdx2Val(SISA); |
1042 | |||
1043 | LOG_DATA("{}: [{}] IODnav [{}], Omega_dot [{} rad/s], delta_n [{:.3e} rad/s], Cuc [{:.3e} rad], Cus [{:.3e} rad/s], Crc [{:.3e} m], Crs [{:.3e} m], SISA [{:.3e} m]", nameId(), satId, | ||
1044 | ephemeris->IODnav, ephemeris->Omega_dot, ephemeris->delta_n, ephemeris->Cuc, ephemeris->Cus, ephemeris->Crc, ephemeris->Crs, ephemeris->signalAccuracy); | ||
1045 | |||
1046 |
1/2✓ Branch 4 taken 225 times.
✗ Branch 5 not taken.
|
225 | finishWord(ephemeris, wordType, ephemerisBuilder->get().subframes); |
1047 | 225 | } | |
1048 |
2/2✓ Branch 0 taken 237 times.
✓ Branch 1 taken 2649 times.
|
2886 | else if (wordType == 4) // SVID, Ephemeris (4/4), and Clock correction parameters |
1049 | { | ||
1050 | // Galileo-OS-SIS-ICD-v2.0: ch. 4.3.5, Table 43 Bits Allocation for I/NAV Word Type 4, p. 38 | ||
1051 | // | ||
1052 | // Even/Odd PageType WordType IODnav SVID Cic Cic Cis toc toc af0 af0 af1 Tail Pad Even/Odd PageType af1 af2 Spare Reserved 1 | ||
1053 | // 1 1 6 10 6 8 8 16 8 6 26 5 13 6 8 1 1 8 6 2 14 | ||
1054 | // └───────────────────────┬─────────────────────┘ └─────┬─────┘ └──┬───┘ └────────┬────────┘ └───────────────────────┬─────────────────────┘ | ||
1055 | // Ublox 1 2 3 4 5 | ||
1056 | |||
1057 | // Galileo-OS-SIS-ICD-v2.0: ch. 5.1.1, Table 60 Ephemeris Parameters, p. 43f | ||
1058 | // Galileo-OS-SIS-ICD-v2.0: ch. 5.1.3, Table 63 Galileo Clock Correction Parameters, p. 46 | ||
1059 | // > Cic, Cis, af0, af1, af2 shall be two's complement, with the sign bit (+ or -) occupying the MSB | ||
1060 | |||
1061 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 1 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1062 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto IODnav = static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 14) & 0b1111111111); |
1063 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | [[maybe_unused]] auto SVID = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 8) & 0b111111); |
1064 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto Cic = static_cast<int16_t>((sfrbx.dwrd.at(w) & 0b11111111) << 8); |
1065 | LOG_DATA("{}: [{}] IODnav {}, SVID {}, Cic {}", nameId(), satId, IODnav, SVID, std::bitset<16>(static_cast<uint16_t>(Cic))); | ||
1066 | |||
1067 | 237 | w++; | |
1068 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 2 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1069 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | Cic |= static_cast<int16_t>((sfrbx.dwrd.at(w) >> 24) & 0b11111111); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) |
1070 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto Cis = static_cast<int16_t>((sfrbx.dwrd.at(w) >> 8) & 0b1111111111111111); |
1071 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto toc = static_cast<uint16_t>((sfrbx.dwrd.at(w) & 0b11111111) << 6); |
1072 | LOG_DATA("{}: [{}] Cic {} ({}), Cis {}, toc {}", nameId(), satId, Cic, std::bitset<16>(static_cast<uint16_t>(Cic)), Cis, std::bitset<16>(toc)); | ||
1073 | |||
1074 | 237 | w++; | |
1075 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 3 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1076 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | toc |= static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 26) & 0b111111); |
1077 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto af0 = static_cast<int32_t>((sfrbx.dwrd.at(w) & 0b11111111111111111111111111) << 5); |
1078 | LOG_DATA("{}: [{}] toc {} ({}), af0 {}", nameId(), satId, toc, std::bitset<16>(toc), std::bitset<32>(static_cast<uint32_t>(af0))); | ||
1079 | |||
1080 | 237 | w++; | |
1081 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 4 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1082 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | af0 |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 27) & 0b11111); |
1083 | 237 | af0 = math::interpretAs<int32_t, 31>(af0); | |
1084 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto af1 = static_cast<int32_t>(((sfrbx.dwrd.at(w) >> 14) & 0b1111111111111) << 8); |
1085 | LOG_DATA("{}: [{}] af0 {} ({}), af1 {}", nameId(), satId, af0, std::bitset<32>(static_cast<uint32_t>(af0)), std::bitset<32>(static_cast<uint32_t>(af1))); | ||
1086 | |||
1087 | 237 | w++; | |
1088 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 5 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1089 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | af1 |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 22) & 0b11111111); |
1090 | 237 | af1 = math::interpretAs<int32_t, 21>(af1); | |
1091 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto af2 = math::interpretAs<int8_t, 6>(sfrbx.dwrd.at(w) >> 16); |
1092 | LOG_DATA("{}: [{}] af1 {} ({}), af1 {}", nameId(), satId, af1, std::bitset<32>(static_cast<uint32_t>(af1)), std::bitset<8>(static_cast<uint8_t>(af2))); | ||
1093 | |||
1094 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto ephemerisBuilder = getEphemerisBuilder(satId, IODnav); |
1095 |
2/2✓ Branch 1 taken 28 times.
✓ Branch 2 taken 209 times.
|
237 | if (!ephemerisBuilder.has_value()) |
1096 | { | ||
1097 | LOG_DATA("{}: [{}] Could not find Ephemeris builder for IODnav {}", nameId(), satId, IODnav); | ||
1098 | 28 | return; | |
1099 | } | ||
1100 | 209 | auto ephemeris = std::dynamic_pointer_cast<GalileoEphemeris>(ephemerisBuilder->get().navData); | |
1101 | |||
1102 |
1/2✓ Branch 2 taken 209 times.
✗ Branch 3 not taken.
|
209 | InsTime insTimeToc(gpsWeekToW.gpsCycle, gpsWeekToW.gpsWeek, toc * 60.0, GST); |
1103 | |||
1104 | 209 | ephemeris->Cic = Cic * std::pow(2.0, -29); | |
1105 | 209 | ephemeris->Cis = Cis * std::pow(2.0, -29); | |
1106 | 209 | ephemeris->toc = insTimeToc; | |
1107 | 209 | ephemeris->refTime = ephemeris->toc; | |
1108 | 209 | ephemeris->a = { | |
1109 | 209 | af0 * std::pow(2, -34), | |
1110 | 209 | af1 * std::pow(2, -46), | |
1111 | 209 | af2 * std::pow(2, -59), | |
1112 | }; | ||
1113 | |||
1114 | LOG_DATA("{}: [{}] IODnav [{}], Cic [{:.3e} rad], Cis [{:.3e} rad]", nameId(), satId, ephemeris->IODnav, ephemeris->Cic, ephemeris->Cis); | ||
1115 | LOG_DATA("{}: [{}] toc [{}], a0 [{:.3e} s], a1 [{:.3e} s/s], a2 [{:.3e} s/s^2]", nameId(), satId, | ||
1116 | ephemeris->toc.toYMDHMS(GPST), ephemeris->a[0], ephemeris->a[1], ephemeris->a[2]); | ||
1117 | |||
1118 |
1/2✓ Branch 4 taken 209 times.
✗ Branch 5 not taken.
|
209 | finishWord(ephemeris, wordType, ephemerisBuilder->get().subframes); |
1119 | 209 | } | |
1120 |
2/2✓ Branch 0 taken 236 times.
✓ Branch 1 taken 2413 times.
|
2649 | else if (wordType == 5) // Ionospheric correction, BGD, signal health and data validity status and GST |
1121 | { | ||
1122 | // Galileo-OS-SIS-ICD-v2.0: ch. 4.3.5, Table 44 Bits Allocation for I/NAV Word Type 5, p. 38 | ||
1123 | // | ||
1124 | // Even/Odd PageType WordType ai0 ai1 ai2 ai2 Region 1-5 BGD(E1,E5a) BGD(E1,E5b) BGD(E1,E5b) E5b_HS E1b_HS E5b_DVS E1b_DVS WN TOW TOW Spare Tail Pad Even/Odd PageType Spare Reserved 1 | ||
1125 | // 1 1 6 11 11 2 12 5x1 10 5 5 2 2 1 1 12 9 11 7 13 6 1 1 16 14 | ||
1126 | // └─────────────────────┬───────────────────┘ └───────────────────┬───────────────────┘ └─────────────────────────┬──────────────────────────┘ └─────────┬─────────┘ └──────────────────┬────────────────┘ | ||
1127 | // Ublox 1 2 3 4 5 | ||
1128 | |||
1129 | // Galileo-OS-SIS-ICD-v2.0: ch. 5.1.6, Table 67 Ionospheric Correction Parameters, p. 48 | ||
1130 | // Galileo-OS-SIS-ICD-v2.0: ch. 5.1.5, Table 65 BGD Parameters, p. 47 | ||
1131 | // > ai1, ai2, BGD(E1,E5a), BGD(E1,E5b) shall be two's complement, with the sign bit (+ or -) occupying the MSB | ||
1132 | |||
1133 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 1 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1134 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto ai0 = static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 13) & 0b11111111111); |
1135 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto ai1 = math::interpretAs<int16_t, 11>((sfrbx.dwrd.at(w) >> 2) & 0b11111111111); |
1136 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto ai2 = static_cast<int16_t>((sfrbx.dwrd.at(w) & 0b11) << 12); |
1137 | LOG_DATA("{}: [{}] ai0 {} ({}), ai1 {} ({}), ai2 {}", nameId(), satId, | ||
1138 | ai0, std::bitset<16>(ai0), ai1, std::bitset<16>(static_cast<uint16_t>(ai1)), std::bitset<16>(static_cast<uint16_t>(ai2))); | ||
1139 | |||
1140 | 236 | w++; | |
1141 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 2 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1142 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | ai2 |= static_cast<int16_t>((sfrbx.dwrd.at(w) >> 20) & 0b111111111111); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) |
1143 | 236 | ai2 = math::interpretAs<int16_t, 14>(ai2); | |
1144 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto BGD_E1_E5a = math::interpretAs<int16_t, 10>((sfrbx.dwrd.at(w) >> 5) & 0b1111111111); |
1145 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto BGD_E1_E5b = static_cast<int16_t>((sfrbx.dwrd.at(w) & 0b11111) << 5); |
1146 | LOG_DATA("{}: [{}] ai2 {} ({}), BGD_E1_E5a {}, BGD_E1_E5b {}", nameId(), satId, ai2, std::bitset<16>(static_cast<uint16_t>(ai2)), BGD_E1_E5a, std::bitset<16>(static_cast<uint16_t>(BGD_E1_E5b))); | ||
1147 | |||
1148 | 236 | w++; | |
1149 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 3 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1150 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | BGD_E1_E5b |= static_cast<int16_t>((sfrbx.dwrd.at(w) >> 27) & 0b11111); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) |
1151 | 236 | BGD_E1_E5b = math::interpretAs<int16_t, 10>(BGD_E1_E5b); | |
1152 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto E5b_HS = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 25) & 0b11); |
1153 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto E1b_HS = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 23) & 0b11); |
1154 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto E5b_DVS = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 22) & 0b1); |
1155 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto E1b_DVS = static_cast<uint8_t>((sfrbx.dwrd.at(w) >> 21) & 0b1); |
1156 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | [[maybe_unused]] auto WN = static_cast<uint16_t>((sfrbx.dwrd.at(w) >> 9) & 0b111111111111); |
1157 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | [[maybe_unused]] uint32_t TOW = (sfrbx.dwrd.at(w) & 0b111111111) << 11; |
1158 | LOG_DATA("{}: [{}] BGD_E1_E5b {} ({}), E5b_HS {}, E1b_HS {}, E5b_DVS {}, E1b_DVS {}, WN {}, TOW {}", nameId(), satId, | ||
1159 | BGD_E1_E5b, std::bitset<16>(static_cast<uint16_t>(BGD_E1_E5b)), E5b_HS, E1b_HS, E5b_DVS, E1b_DVS, WN, std::bitset<32>(TOW)); | ||
1160 | |||
1161 | 236 | w++; | |
1162 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 4 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1163 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | TOW |= (sfrbx.dwrd.at(w) >> 21) & 0b11111111111; |
1164 | LOG_DATA("{}: [{}] TOW {} ({})", nameId(), satId, TOW, std::bitset<32>(TOW)); | ||
1165 | |||
1166 | 236 | w++; | |
1167 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 5 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1168 | |||
1169 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | auto ephemerisBuilder = getLastEphemerisBuilder(satId); |
1170 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 233 times.
|
236 | if (!ephemerisBuilder.has_value()) |
1171 | { | ||
1172 | LOG_DATA("{}: [{}] Could not find any ephemeris builder", nameId(), satId); | ||
1173 | 3 | return; | |
1174 | } | ||
1175 | 233 | auto ephemeris = std::dynamic_pointer_cast<GalileoEphemeris>(ephemerisBuilder->get().navData); | |
1176 | |||
1177 | 233 | ephemeris->BGD_E1_E5a = BGD_E1_E5a * std::pow(2.0, -32); | |
1178 | 233 | ephemeris->BGD_E1_E5b = BGD_E1_E5b * std::pow(2.0, -32); | |
1179 | 233 | ephemeris->svHealth = { | |
1180 | .E5a_DataValidityStatus = {}, | ||
1181 | .E5b_DataValidityStatus = static_cast<GalileoEphemeris::SvHealth::DataValidityStatus>(E5b_DVS), | ||
1182 | .E1B_DataValidityStatus = static_cast<GalileoEphemeris::SvHealth::DataValidityStatus>(E1b_DVS), | ||
1183 | .E5a_SignalHealthStatus = {}, | ||
1184 | .E5b_SignalHealthStatus = static_cast<GalileoEphemeris::SvHealth::SignalHealthStatus>(E5b_HS), | ||
1185 | .E1B_SignalHealthStatus = static_cast<GalileoEphemeris::SvHealth::SignalHealthStatus>(E1b_HS), | ||
1186 | }; | ||
1187 | 233 | ephemeris->dataSource[0] = true; // I/NAV E1-B | |
1188 | 233 | ephemeris->dataSource[9] = true; // af0-af2, Toc, SISA are for E5b,E1 | |
1189 | |||
1190 | { | ||
1191 |
1/2✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
|
233 | std::unique_lock guard(outputPins.at(OUTPUT_PORT_INDEX_GNSS_NAV_INFO).dataAccessMutex, std::defer_lock); |
1192 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 233 times.
|
233 | if (!_postProcessingLock.has_value()) |
1193 | { | ||
1194 | ✗ | guard.lock(); | |
1195 | } | ||
1196 | |||
1197 |
3/4✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 232 times.
|
233 | if (!_gnssNavInfo.ionosphericCorrections.contains(satId.satSys, IonosphericCorrections::Alpha)) |
1198 | { | ||
1199 |
4/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
|
1 | LOG_DEBUG("{}: [{}] Received Ionospheric corrections [{}]", nameId(), satId.satSys, ephemeris->refTime.toYMDHMS(GPST)); |
1200 | } | ||
1201 | |||
1202 | // ‘sfu’ (solar flux unit) is not a SI unit but can be converted as: 1 sfu = 10e-22 W/(m2*Hz) | ||
1203 | ✗ | _gnssNavInfo.ionosphericCorrections.insert(satId.satSys, IonosphericCorrections::Alpha, | |
1204 | { | ||
1205 | 233 | ai0 * std::pow(2.0, -2) /* [sfu] */, | |
1206 | 233 | ai1 * std::pow(2.0, -8) /* [sfu/degree] */, | |
1207 |
1/2✓ Branch 2 taken 233 times.
✗ Branch 3 not taken.
|
233 | ai2 * std::pow(2.0, -15) /* [sfu/degree^2] */, |
1208 | 0.0, | ||
1209 | }); | ||
1210 | 233 | } | |
1211 | |||
1212 | LOG_DATA("{}: [{}] BGD_E1_E5a [{:.3e} s], BGD_E1_E5b [{:.3e} rad]", nameId(), satId, ephemeris->BGD_E1_E5a, ephemeris->BGD_E1_E5b); | ||
1213 | |||
1214 |
1/2✓ Branch 4 taken 233 times.
✗ Branch 5 not taken.
|
233 | finishWord(ephemeris, wordType, ephemerisBuilder->get().subframes); |
1215 | 233 | } | |
1216 |
2/2✓ Branch 0 taken 237 times.
✓ Branch 1 taken 2176 times.
|
2413 | else if (wordType == 6) // GST-UTC conversion parameters |
1217 | { | ||
1218 | // Galileo-OS-SIS-ICD-v2.0: ch. 4.3.5, Table 44 Bits Allocation for I/NAV Word Type 6, p. 38 | ||
1219 | // | ||
1220 | // Even/Odd PageType WordType A0 A0 A1 dt_LS t0t WNot WN_LSF DN dt_LSF TOW Tail Pad Even/Odd PageType TOW Spare Reserved 1 | ||
1221 | // 1 1 6 24 8 24 8 8 8 8 3 8 7 6 8 1 1 13 3 14 | ||
1222 | // └───────────────┬──────────────┘ └──┬─┘ └──────────┬───────────┘ └────────────┬───────────┘ └────────────────────┬───────────────────┘ | ||
1223 | // Ublox 1 2 3 4 5 | ||
1224 | |||
1225 | // Galileo-OS-SIS-ICD-v2.0: ch. 5.1.7, Table 68 Ionospheric Correction Parameters, p. 49 | ||
1226 | // > A0, A1, dt_LS, dt_LSF shall be two's complement, with the sign bit (+ or -) occupying the MSB | ||
1227 | |||
1228 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 1 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1229 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto A0 = static_cast<int32_t>((sfrbx.dwrd.at(w) & 0b111111111111111111111111) << 8); |
1230 | LOG_DATA("{}: [{}] A0 {}", nameId(), satId, std::bitset<32>(static_cast<uint32_t>(A0))); | ||
1231 | |||
1232 | 237 | w++; | |
1233 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 2 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1234 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | A0 |= static_cast<int32_t>((sfrbx.dwrd.at(w) >> 24) & 0b11111111); |
1235 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto A1 = math::interpretAs<int32_t, 24>(sfrbx.dwrd.at(w) & 0b111111111111111111111111); |
1236 | LOG_DATA("{}: [{}] A0 {} ({}), A1 {} ({})", nameId(), satId, A0, std::bitset<32>(static_cast<uint32_t>(A0)), A1, std::bitset<32>(static_cast<uint32_t>(A1))); | ||
1237 | |||
1238 | 237 | w++; | |
1239 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 3 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1240 | |||
1241 | 237 | w++; | |
1242 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 4 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1243 | |||
1244 | 237 | w++; | |
1245 | LOG_DATA("{}: [{}] word {:2}: {}", nameId(), satId, w + 1 /* 5 */, std::bitset<32>(sfrbx.dwrd.at(w))); | ||
1246 | |||
1247 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | std::unique_lock guard(outputPins.at(OUTPUT_PORT_INDEX_GNSS_NAV_INFO).dataAccessMutex, std::defer_lock); |
1248 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 237 times.
|
237 | if (!_postProcessingLock.has_value()) |
1249 | { | ||
1250 | ✗ | guard.lock(); | |
1251 | } | ||
1252 | |||
1253 |
1/2✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
|
237 | auto key = std::make_pair(satId.satSys.getTimeSystem(), UTC); |
1254 |
3/4✓ Branch 2 taken 237 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 236 times.
|
237 | if (!_gnssNavInfo.timeSysCorr.contains(key)) |
1255 | { | ||
1256 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
2 | if (auto ephemerisBuilder = getLastEphemerisBuilder(satId); |
1257 | 1 | ephemerisBuilder.has_value()) | |
1258 | { | ||
1259 | ✗ | auto ephemeris = std::dynamic_pointer_cast<GalileoEphemeris>(ephemerisBuilder->get().navData); | |
1260 | ✗ | LOG_DEBUG("{}: [{}] Received Time system corrections [{}]", nameId(), satId.satSys, ephemeris->refTime.toYMDHMS(GPST)); | |
1261 | ✗ | } | |
1262 | else | ||
1263 | { | ||
1264 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | LOG_DEBUG("{}: [{}] Received Time system corrections", nameId(), satId.satSys); |
1265 | } | ||
1266 | } | ||
1267 | |||
1268 |
1/2✓ Branch 2 taken 237 times.
✗ Branch 3 not taken.
|
237 | _gnssNavInfo.timeSysCorr[key] = GnssNavInfo::TimeSystemCorrections{ |
1269 | 237 | .a0 = A0 * std::pow(2, -30), | |
1270 | 237 | .a1 = A1 * std::pow(2, -50), | |
1271 | }; | ||
1272 | 237 | } | |
1273 | } | ||
1274 | |||
1275 | ✗ | void NAV::UbloxGnssOrbitCollector::decryptGLONASS([[maybe_unused]] const SatId& satId, const ubx::UbxRxmSfrbx& /* sfrbx */, const InsTime& /* insTime */) | |
1276 | { | ||
1277 | // u-blox 8 / u-blox M8: Receiver description - Including protocol specification, ch. 10.3, p. 31 | ||
1278 | // > For GLONASS L1OF and L2OF signals, each reported subframe contains a string as described in | ||
1279 | // > the GLONASS ICD. This string comprises 85 data bits which are reported over three 32 bit words | ||
1280 | // > in the UBX-RXM-SFRBX message. Data bits 1 to 8 are always a hamming code, whilst bits 81 to 84 | ||
1281 | // > are a string number and bit 85 is the idle chip, which should always have a value of zero. The | ||
1282 | // > meaning of other bits vary with string and frame number. | ||
1283 | // > The fourth and final 32 bit word in the UBX-RXM-SFRBX message contains frame and superframe | ||
1284 | // > numbers (where available). These values aren't actually transmitted by the SVs, but are deduced | ||
1285 | // > by the receiver and are included to aid decoding of the transmitted data. However, the receiver | ||
1286 | // > does not always know these values, in which case a value of zero is reported. | ||
1287 | // > | ||
1288 | // > MSB LSB | ||
1289 | // > 1: Idle chip (1 bit, always 0) String # (4 bits) Data (80 - 54) (27 bits) | ||
1290 | // > 2: Data (53 - 22) (32 bits) | ||
1291 | // > 3: Data (21 - 9) (13 bits) Hammering code (8 bits) Pad (11 bits) | ||
1292 | // > 4: Superframe # (16 bits) Pad (8 bits) Frame # (8 bits) | ||
1293 | // > | ||
1294 | // > In some circumstances, (especially on startup) the receiver may be able to decode data from a | ||
1295 | // > GLONASS SV before it can identify the SV. When this occurs UBX-RXM-SFRBX messages will be | ||
1296 | // > issued with an svId of 255 to indicate "unknown". | ||
1297 | |||
1298 | ✗ | if (!_warningsNotImplemented.contains(satId.satSys)) | |
1299 | { | ||
1300 | ✗ | LOG_WARN("{}: ubx orbit collector is not implemented for GLONASS yet.", nameId()); // TODO: not implemented yet. | |
1301 | ✗ | _warningsNotImplemented.insert(satId.satSys); | |
1302 | } | ||
1303 | |||
1304 | // auto ephemeris = std::dynamic_pointer_cast<GLONASSEphemeris>(ephemerisBuilder->get().navData); | ||
1305 | |||
1306 | // sfrbx.freqId; | ||
1307 | // _gnssNavInfo.addSatelliteNavData({ satSys, satNum }, std::make_shared<GLONASSEphemeris>(epoch, tau_c, | ||
1308 | // -m_tau_n, gamma_n, static_cast<bool>(health), | ||
1309 | // pos, vel, accelLuniSolar, | ||
1310 | // frequencyNumber_accuracyCode)); | ||
1311 | ✗ | } | |
1312 | |||
1313 | ✗ | void NAV::UbloxGnssOrbitCollector::decryptBeiDou([[maybe_unused]] const SatId& satId, const ubx::UbxRxmSfrbx& /* sfrbx */, const InsTime& /* insTime */) | |
1314 | { | ||
1315 | // u-blox 8 / u-blox M8: Receiver description - Including protocol specification, ch. 10.4, p. 32 | ||
1316 | // > For BeiDou (B1I) signals, there is a fairly straightforward mapping between the reported subframe | ||
1317 | // > and the structure of subframe and words described in the BeiDou ICD. Each subframe comprises | ||
1318 | // > ten data words, which are reported in the same order they are received. | ||
1319 | // > | ||
1320 | // > MSB LSB | ||
1321 | // > 1 to 10: Pad (2 bits) Data (22 bits) Parity (8 bits) | ||
1322 | // > | ||
1323 | // > Note that as the BeiDou data words only comprise 30 bits, the 2 most significant bits in each word | ||
1324 | // > reported by UBX-RXM-SFRBX are padding and should be ignored. | ||
1325 | |||
1326 | ✗ | if (!_warningsNotImplemented.contains(satId.satSys)) | |
1327 | { | ||
1328 | ✗ | LOG_WARN("{}: ubx orbit collector is not implemented for BeiDou yet.", nameId()); // TODO: not implemented yet. | |
1329 | ✗ | _warningsNotImplemented.insert(satId.satSys); | |
1330 | } | ||
1331 | |||
1332 | // auto ephemeris = std::dynamic_pointer_cast<BDSEphemeris>(ephemerisBuilder->get().navData); | ||
1333 | |||
1334 | // _gnssNavInfo.addSatelliteNavData({ satSys, satNum }, std::make_shared<BDSEphemeris>(epoch, toe, | ||
1335 | // IODE_IODnav_AODE_IODEC, fitInterval_AODC, a, | ||
1336 | // sqrt_A, e, i_0, Omega_0, omega, M_0, | ||
1337 | // delta_n, Omega_dot, i_dot, Cus, Cuc, | ||
1338 | // Cis, Cic, Crs, Crc, | ||
1339 | // signalAccuracy, svHealth, | ||
1340 | // tgd_bgd5a_TGD1, IODC_bgd5b_TGD2)); | ||
1341 | ✗ | } | |
1342 | |||
1343 | ✗ | void NAV::UbloxGnssOrbitCollector::decryptQZSS([[maybe_unused]] const SatId& satId, const ubx::UbxRxmSfrbx& /* sfrbx */, const InsTime& /* insTime */) | |
1344 | { | ||
1345 | // u-blox 8 / u-blox M8: Receiver description - Including protocol specification, ch. 10.7, p. 34 | ||
1346 | // > The structure of the data delivered by QZSS L1C/A signals is effectively identical to that of GPS | ||
1347 | // > (L1C/A). Similarly the QZSS L2C signal is effectively identical to the GPS (L2C). | ||
1348 | // > The QZSS (L1SAIF) signal is different and uses the same data block format as used by SBAS | ||
1349 | // > (L1C/A). QZSS (SAIF) signals can be distinguished from QZSS (L1C/A and L2C) by noting that they | ||
1350 | // > have 8 words, instead of 10 for QZSS (L1C/A and L2C). | ||
1351 | |||
1352 | ✗ | if (!_warningsNotImplemented.contains(satId.satSys)) | |
1353 | { | ||
1354 | ✗ | LOG_WARN("{}: ubx orbit collector is not implemented for QZSS yet.", nameId()); // TODO: not implemented yet. | |
1355 | ✗ | _warningsNotImplemented.insert(satId.satSys); | |
1356 | } | ||
1357 | ✗ | } | |
1358 | |||
1359 | ✗ | void NAV::UbloxGnssOrbitCollector::decryptIRNSS([[maybe_unused]] const SatId& satId, const ubx::UbxRxmSfrbx& /* sfrbx */, const InsTime& /* insTime */) | |
1360 | { | ||
1361 | ✗ | if (!_warningsNotImplemented.contains(satId.satSys)) | |
1362 | { | ||
1363 | ✗ | LOG_WARN("{}: ubx orbit collector is not implemented for IRNSS yet.", nameId()); // TODO: not implemented yet. | |
1364 | ✗ | _warningsNotImplemented.insert(satId.satSys); | |
1365 | } | ||
1366 | ✗ | } | |
1367 | |||
1368 | ✗ | void NAV::UbloxGnssOrbitCollector::decryptSBAS([[maybe_unused]] const SatId& satId, const ubx::UbxRxmSfrbx& /* sfrbx */, const InsTime& /* insTime */) | |
1369 | { | ||
1370 | // u-blox 8 / u-blox M8: Receiver description - Including protocol specification, ch. 10.6, p. 33f | ||
1371 | |||
1372 | ✗ | if (!_warningsNotImplemented.contains(satId.satSys)) | |
1373 | { | ||
1374 | ✗ | LOG_WARN("{}: ubx orbit collector is not implemented for SBAS yet.", nameId()); // TODO: not implemented yet. | |
1375 | ✗ | _warningsNotImplemented.insert(satId.satSys); | |
1376 | } | ||
1377 | ✗ | } | |
1378 |