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 "UartPacketConverter.hpp" | ||
10 | |||
11 | #include <memory> | ||
12 | |||
13 | #include "util/Logger.hpp" | ||
14 | #include "util/Time/TimeBase.hpp" | ||
15 | |||
16 | #include "internal/NodeManager.hpp" | ||
17 | namespace nm = NAV::NodeManager; | ||
18 | #include "internal/FlowManager.hpp" | ||
19 | |||
20 | #include "util/Vendor/Ublox/UbloxUtilities.hpp" | ||
21 | #include "util/Vendor/Emlid/EmlidUtilities.hpp" | ||
22 | #include "util/Vendor/Espressif/EspressifUtilities.hpp" | ||
23 | |||
24 | #include "Nodes/DataProvider/IMU/Sensors/VectorNavSensor.hpp" | ||
25 | |||
26 | #include "NodeData/General/UartPacket.hpp" | ||
27 | #include "NodeData/GNSS/UbloxObs.hpp" | ||
28 | #include "NodeData/GNSS/EmlidObs.hpp" | ||
29 | #include "NodeData/WiFi/WiFiObs.hpp" | ||
30 | |||
31 | 112 | NAV::UartPacketConverter::UartPacketConverter() | |
32 |
2/4✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
|
112 | : Node(typeStatic()) |
33 | { | ||
34 | LOG_TRACE("{}: called", name); | ||
35 | 112 | _hasConfig = true; | |
36 | 112 | _guiConfigDefaultWindowSize = { 340, 93 }; | |
37 | |||
38 |
4/8✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 112 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 112 times.
✓ Branch 10 taken 112 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
448 | nm::CreateOutputPin(this, "UbloxObs", Pin::Type::Flow, { NAV::UbloxObs::type() }); |
39 | |||
40 |
4/8✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 112 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 112 times.
✓ Branch 9 taken 112 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
336 | nm::CreateInputPin(this, "UartPacket", Pin::Type::Flow, { NAV::UartPacket::type() }, &UartPacketConverter::receiveObs); |
41 | 336 | } | |
42 | |||
43 | 224 | NAV::UartPacketConverter::~UartPacketConverter() | |
44 | { | ||
45 | LOG_TRACE("{}: called", nameId()); | ||
46 | 224 | } | |
47 | |||
48 | 224 | std::string NAV::UartPacketConverter::typeStatic() | |
49 | { | ||
50 |
1/2✓ Branch 1 taken 224 times.
✗ Branch 2 not taken.
|
448 | return "UartPacketConverter"; |
51 | } | ||
52 | |||
53 | ✗ | std::string NAV::UartPacketConverter::type() const | |
54 | { | ||
55 | ✗ | return typeStatic(); | |
56 | } | ||
57 | |||
58 | 112 | std::string NAV::UartPacketConverter::category() | |
59 | { | ||
60 |
1/2✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
224 | return "Converter"; |
61 | } | ||
62 | |||
63 | ✗ | void NAV::UartPacketConverter::guiConfig() | |
64 | { | ||
65 | ✗ | if (auto outputType = static_cast<int>(_outputType); | |
66 | ✗ | ImGui::Combo(fmt::format("Output Type##{}", size_t(id)).c_str(), &outputType, "UbloxObs\0EmlidObs\0WiFiObs\0\0")) | |
67 | { | ||
68 | ✗ | _outputType = static_cast<decltype(_outputType)>(outputType); | |
69 | ✗ | std::string outputTypeString; | |
70 | ✗ | switch (_outputType) | |
71 | { | ||
72 | ✗ | case OutputType_UbloxObs: | |
73 | ✗ | outputTypeString = "UbloxObs"; | |
74 | ✗ | break; | |
75 | ✗ | case OutputType_EmlidObs: | |
76 | ✗ | outputTypeString = "EmlidObs"; | |
77 | ✗ | break; | |
78 | ✗ | default: | |
79 | ✗ | outputTypeString = "WiFiObs"; | |
80 | } | ||
81 | |||
82 | ✗ | LOG_DEBUG("{}: Output Type changed to {}", nameId(), outputTypeString); | |
83 | |||
84 | ✗ | if (_outputType == OutputType_UbloxObs) | |
85 | { | ||
86 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::UbloxObs::type() }; | |
87 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::UbloxObs::type(); | |
88 | } | ||
89 | ✗ | else if (_outputType == OutputType_EmlidObs) | |
90 | { | ||
91 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::EmlidObs::type() }; | |
92 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::EmlidObs::type(); | |
93 | } | ||
94 | ✗ | else if (_outputType == OutputType_WiFiObs) | |
95 | { | ||
96 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::WiFiObs::type() }; | |
97 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::WiFiObs::type(); | |
98 | } | ||
99 | |||
100 | ✗ | for (auto& link : outputPins.front().links) | |
101 | { | ||
102 | ✗ | if (auto* connectedPin = link.getConnectedPin()) | |
103 | { | ||
104 | ✗ | outputPins.front().recreateLink(*connectedPin); | |
105 | } | ||
106 | } | ||
107 | ✗ | flow::ApplyChanges(); | |
108 | ✗ | } | |
109 | |||
110 | ✗ | if (_outputType == OutputType_WiFiObs) | |
111 | { | ||
112 | ✗ | if (ImGui::Checkbox(fmt::format("Show SyncIn Pin##{}", size_t(id)).c_str(), &_syncInPin)) | |
113 | { | ||
114 | ✗ | LOG_DEBUG("{}: syncInPin changed to {}", nameId(), _syncInPin); | |
115 | ✗ | flow::ApplyChanges(); | |
116 | ✗ | if (_syncInPin && (inputPins.size() <= 1)) | |
117 | { | ||
118 | ✗ | nm::CreateInputPin(this, "SyncIn", Pin::Type::Object, { "TimeSync" }); | |
119 | } | ||
120 | ✗ | else if (!_syncInPin) | |
121 | { | ||
122 | ✗ | nm::DeleteInputPin(inputPins.at(INPUT_PORT_INDEX_SYNC_IN)); | |
123 | } | ||
124 | } | ||
125 | // Remove the extra flow::ApplyChanges() statement here | ||
126 | } | ||
127 | ✗ | else if (inputPins.size() > 1) | |
128 | { | ||
129 | ✗ | nm::DeleteInputPin(inputPins.at(INPUT_PORT_INDEX_SYNC_IN)); | |
130 | } | ||
131 | ✗ | } | |
132 | |||
133 | ✗ | [[nodiscard]] json NAV::UartPacketConverter::save() const | |
134 | { | ||
135 | LOG_TRACE("{}: called", nameId()); | ||
136 | |||
137 | ✗ | json j; | |
138 | |||
139 | ✗ | j["outputType"] = _outputType; | |
140 | ✗ | j["syncInPin"] = _syncInPin; | |
141 | |||
142 | ✗ | return j; | |
143 | ✗ | } | |
144 | |||
145 | ✗ | void NAV::UartPacketConverter::restore(json const& j) | |
146 | { | ||
147 | LOG_TRACE("{}: called", nameId()); | ||
148 | |||
149 | ✗ | if (j.contains("outputType")) | |
150 | { | ||
151 | ✗ | j.at("outputType").get_to(_outputType); | |
152 | |||
153 | ✗ | if (!outputPins.empty()) | |
154 | { | ||
155 | ✗ | if (_outputType == OutputType_UbloxObs) | |
156 | { | ||
157 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::UbloxObs::type() }; | |
158 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::UbloxObs::type(); | |
159 | } | ||
160 | ✗ | else if (_outputType == OutputType_EmlidObs) | |
161 | { | ||
162 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::EmlidObs::type() }; | |
163 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::EmlidObs::type(); | |
164 | } | ||
165 | ✗ | else if (_outputType == OutputType_WiFiObs) | |
166 | { | ||
167 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).dataIdentifier = { NAV::WiFiObs::type() }; | |
168 | ✗ | outputPins.at(OUTPUT_PORT_INDEX_CONVERTED).name = NAV::WiFiObs::type(); | |
169 | } | ||
170 | } | ||
171 | } | ||
172 | ✗ | if (j.contains("syncInPin") && _outputType == OutputType_WiFiObs) | |
173 | { | ||
174 | ✗ | j.at("syncInPin").get_to(_syncInPin); | |
175 | ✗ | if (_syncInPin && inputPins.size() <= 1) | |
176 | { | ||
177 | ✗ | nm::CreateInputPin(this, "SyncIn", Pin::Type::Object, { "TimeSync" }); | |
178 | } | ||
179 | } | ||
180 | ✗ | } | |
181 | |||
182 | ✗ | bool NAV::UartPacketConverter::initialize() | |
183 | { | ||
184 | LOG_TRACE("{}: called", nameId()); | ||
185 | |||
186 | ✗ | return true; | |
187 | } | ||
188 | |||
189 | ✗ | void NAV::UartPacketConverter::receiveObs(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */) | |
190 | { | ||
191 | ✗ | auto uartPacket = std::static_pointer_cast<const UartPacket>(queue.extract_front()); | |
192 | |||
193 | ✗ | std::shared_ptr<NodeData> convertedData = nullptr; | |
194 | ✗ | if (_outputType == OutputType_UbloxObs) | |
195 | { | ||
196 | ✗ | auto obs = std::make_shared<UbloxObs>(); | |
197 | ✗ | auto packet = uartPacket->raw; | |
198 | ✗ | if (!vendor::ublox::decryptUbloxObs(obs, packet, nameId())) { return; }; | |
199 | ✗ | convertedData = obs; | |
200 | ✗ | } | |
201 | ✗ | else if (_outputType == OutputType_WiFiObs) | |
202 | { | ||
203 | ✗ | auto obs = std::make_shared<WiFiObs>(); | |
204 | ✗ | auto packet = uartPacket->raw; | |
205 | |||
206 | ✗ | vendor::espressif::decryptWiFiObs(obs, packet, nameId()); | |
207 | ✗ | if (_syncInPin && inputPins.at(1).isPinLinked()) | |
208 | { | ||
209 | ✗ | auto timeSyncMaster = getInputValue<const NAV::VectorNavSensor::TimeSync>(0); | |
210 | ✗ | if (_lastSyncInCnt > obs->timeOutputs.syncInCnt) // reset of the slave | |
211 | { | ||
212 | ✗ | _syncOutCntCorr = 0; | |
213 | ✗ | _syncInCntCorr = timeSyncMaster->v->syncOutCnt; | |
214 | } | ||
215 | ✗ | else if (_lastSyncOutCnt > timeSyncMaster->v->syncOutCnt) // reset of the master | |
216 | { | ||
217 | ✗ | _syncInCntCorr = 0; | |
218 | ✗ | _syncOutCntCorr = obs->timeOutputs.syncInCnt; | |
219 | } | ||
220 | ✗ | else if (_lastSyncOutCnt == 0 && timeSyncMaster->v->syncOutCnt > 1) // slave counter started later | |
221 | { | ||
222 | ✗ | _syncInCntCorr = timeSyncMaster->v->syncOutCnt; | |
223 | } | ||
224 | ✗ | else if (_lastSyncOutCnt == 0 && obs->timeOutputs.syncInCnt > 1) // master counter started later | |
225 | { | ||
226 | ✗ | _syncOutCntCorr = obs->timeOutputs.syncInCnt; | |
227 | } | ||
228 | ✗ | _lastSyncOutCnt = timeSyncMaster->v->syncOutCnt; | |
229 | ✗ | _lastSyncInCnt = obs->timeOutputs.syncInCnt; | |
230 | ✗ | int64_t syncCntDiff = obs->timeOutputs.syncInCnt + _syncInCntCorr - timeSyncMaster->v->syncOutCnt - _syncOutCntCorr; | |
231 | ✗ | obs->insTime = timeSyncMaster->v->ppsTime + std::chrono::microseconds(obs->timeOutputs.timeSyncIn) | |
232 | ✗ | + std::chrono::seconds(syncCntDiff); | |
233 | // LOG_DATA("{}: Syncing time {}, pps {}, syncOutCnt {}, syncInCnt {}, syncCntDiff {}, syncInCntCorr {}, syncOutCntCorr {}", | ||
234 | // nameId(), obs->insTime.toGPSweekTow(), timeSyncMaster->ppsTime.toGPSweekTow(), | ||
235 | // timeSyncMaster->syncOutCnt, obs->timeOutputs.syncInCnt, syncCntDiff, _syncInCntCorr, _syncOutCntCorr); | ||
236 | ✗ | } | |
237 | ✗ | convertedData = obs; | |
238 | ✗ | } | |
239 | else /* if (_outputType == OutputType_EmlidObs) */ | ||
240 | { | ||
241 | ✗ | auto obs = std::make_shared<EmlidObs>(); | |
242 | ✗ | auto packet = uartPacket->raw; | |
243 | ✗ | vendor::emlid::decryptEmlidObs(obs, packet); | |
244 | ✗ | convertedData = obs; | |
245 | ✗ | } | |
246 | |||
247 | ✗ | if (!convertedData->insTime.empty()) | |
248 | { | ||
249 | ✗ | if (util::time::GetMode() == util::time::Mode::REAL_TIME) | |
250 | { | ||
251 | ✗ | util::time::SetCurrentTime(convertedData->insTime); | |
252 | } | ||
253 | } | ||
254 | ✗ | else if (auto currentTime = util::time::GetCurrentInsTime(); | |
255 | ✗ | !currentTime.empty()) | |
256 | { | ||
257 | ✗ | convertedData->insTime = currentTime; | |
258 | } | ||
259 | |||
260 | ✗ | if (convertedData) | |
261 | { | ||
262 | ✗ | invokeCallbacks(OUTPUT_PORT_INDEX_CONVERTED, convertedData); | |
263 | } | ||
264 | ✗ | } | |
265 |