0.4.1
Loading...
Searching...
No Matches
KvhFile.cpp
Go to the documentation of this file.
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 "KvhFile.hpp"
10
11#include "util/Logger.hpp"
12
14namespace nm = NAV::NodeManager;
16
18
20
23{
24 LOG_TRACE("{}: called", name);
25
26 _hasConfig = true;
27 _guiConfigDefaultWindowSize = { 380, 70 };
28
30 nm::CreateOutputPin(this, "Header Columns", Pin::Type::Object, { "std::vector<std::string>" }, &_headerColumns);
31}
32
34{
35 LOG_TRACE("{}: called", nameId());
36}
37
39{
40 return "KvhFile";
41}
42
43std::string NAV::KvhFile::type() const
44{
45 return typeStatic();
46}
47
49{
50 return "Data Provider";
51}
52
54{
55 if (auto res = FileReader::guiConfig(".csv,.*", { ".csv" }, size_t(id), nameId()))
56 {
57 LOG_DEBUG("{}: Path changed to {}", nameId(), _path);
59 if (res == FileReader::PATH_CHANGED)
60 {
62 }
63 else
64 {
66 }
67 }
68
70
72 {
73 // Header info
74 if (ImGui::BeginTable(fmt::format("##VectorNavHeaders ({})", id.AsPointer()).c_str(), 2,
75 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
76 {
77 ImGui::TableSetupColumn("Basic", ImGuiTableColumnFlags_WidthFixed);
78 ImGui::TableSetupColumn("IMU", ImGuiTableColumnFlags_WidthFixed);
79 ImGui::TableHeadersRow();
80
81 auto TextColoredIfExists = [this](int index, const char* displayText, const char* searchText, bool alwaysNormal = false) {
82 ImGui::TableSetColumnIndex(index);
83 if (alwaysNormal || std::ranges::find(_headerColumns, searchText) != _headerColumns.end())
84 {
85 ImGui::TextUnformatted(displayText);
86 }
87 else
88 {
89 ImGui::TextDisabled("%s", displayText);
90 }
91 };
92
93 ImGui::TableNextRow();
94 TextColoredIfExists(0, "GpsTime", "GpsToW [s]");
95 TextColoredIfExists(1, "UnCompMag", "UnCompMagX [Gauss]");
96 ImGui::TableNextRow();
97 TextColoredIfExists(0, "TimeStartup", "TimeStartup [ns]");
98 TextColoredIfExists(1, "UnCompAcc", "UnCompAccX [m/s^2]");
99 ImGui::TableNextRow();
100 TextColoredIfExists(0, "Temperature", "Temperature [Celsius]");
101 TextColoredIfExists(1, "UnCompGyro", "UnCompGyroX [rad/s]");
102 ImGui::TableNextRow();
103 TextColoredIfExists(0, "Status", "Status");
104 ImGui::TableNextRow();
105 TextColoredIfExists(0, "SequenceNumber", "SequenceNumber");
106
107 ImGui::EndTable();
108 }
109 }
110 else if (_fileType == FileType::BINARY)
111 {
112 ImGui::TextUnformatted("Binary file");
113 }
114}
115
116[[nodiscard]] json NAV::KvhFile::save() const
117{
118 LOG_TRACE("{}: called", nameId());
119
120 json j;
121
122 j["FileReader"] = FileReader::save();
123 j["Imu"] = Imu::save();
124
125 return j;
126}
127
129{
130 LOG_TRACE("{}: called", nameId());
131
132 if (j.contains("FileReader"))
133 {
134 FileReader::restore(j.at("FileReader"));
135 }
136 if (j.contains("Imu"))
137 {
138 Imu::restore(j.at("Imu"));
139 }
140}
141
143{
144 LOG_TRACE("{}: called", nameId());
145
146 return FileReader::initialize();
147}
148
150{
151 LOG_TRACE("{}: called", nameId());
152
154}
155
157{
159
160 return true;
161}
162
163std::shared_ptr<const NAV::NodeData> NAV::KvhFile::pollData()
164{
165 std::shared_ptr<KvhObs> obs = nullptr;
166
168 {
169 uint8_t i = 0;
170 std::unique_ptr<uart::protocol::Packet> packet = nullptr;
171 while (!eof() && read(reinterpret_cast<char*>(&i), 1))
172 {
173 packet = _sensor.findPacket(i);
174
175 if (packet != nullptr)
176 {
177 break;
178 }
179 }
180
181 if (!packet)
182 {
183 return nullptr;
184 }
185
186 obs = std::make_shared<KvhObs>(_imuPos, *packet);
187
188 // Check if package is empty
189 if (obs->raw.getRawDataLength() == 0)
190 {
191 return nullptr;
192 }
193
195 }
196 else if (_fileType == FileType::ASCII)
197 {
198 obs = std::make_shared<KvhObs>(_imuPos);
199
200 // Read line
201 std::string line;
202 getline(line);
203 // Remove any starting non text characters
204 line.erase(line.begin(), std::ranges::find_if(line, [](int ch) { return std::isgraph(ch); }));
205
206 if (line.empty())
207 {
208 return nullptr;
209 }
210
211 // Convert line into stream
212 std::stringstream lineStream(line);
213 std::string cell;
214
215 std::optional<uint16_t> gpsCycle = 0;
216 std::optional<uint16_t> gpsWeek;
217 std::optional<long double> gpsToW;
218 std::optional<double> magX;
219 std::optional<double> magY;
220 std::optional<double> magZ;
221 std::optional<double> accelX;
222 std::optional<double> accelY;
223 std::optional<double> accelZ;
224 std::optional<double> gyroX;
225 std::optional<double> gyroY;
226 std::optional<double> gyroZ;
227
228 // Split line at comma
229 for (const auto& column : _headerColumns)
230 {
231 if (std::getline(lineStream, cell, ','))
232 {
233 // Remove any trailing non text characters
234 cell.erase(std::ranges::find_if(cell, [](int ch) { return std::iscntrl(ch); }), cell.end());
235 if (cell.empty())
236 {
237 continue;
238 }
239
240 if (column == "GpsCycle")
241 {
242 gpsCycle = static_cast<uint16_t>(std::stoul(cell));
243 }
244 else if (column == "GpsWeek")
245 {
246 gpsWeek = static_cast<uint16_t>(std::stoul(cell));
247 }
248 else if (column == "GpsToW [s]")
249 {
250 gpsToW = std::stold(cell);
251 }
252 else if (column == "MagX [Gauss]")
253 {
254 magX = std::stod(cell);
255 }
256 else if (column == "MagY [Gauss]")
257 {
258 magY = std::stod(cell);
259 }
260 else if (column == "MagZ [Gauss]")
261 {
262 magZ = std::stod(cell);
263 }
264 else if (column == "AccX [m/s^2]")
265 {
266 accelX = std::stod(cell);
267 }
268 else if (column == "AccY [m/s^2]")
269 {
270 accelY = std::stod(cell);
271 }
272 else if (column == "AccZ [m/s^2]")
273 {
274 accelZ = std::stod(cell);
275 }
276 else if (column == "GyroX [rad/s]")
277 {
278 gyroX = std::stod(cell);
279 }
280 else if (column == "GyroY [rad/s]")
281 {
282 gyroY = std::stod(cell);
283 }
284 else if (column == "GyroZ [rad/s]")
285 {
286 gyroZ = std::stod(cell);
287 }
288 else if (column == "Temperature [Celsius]")
289 {
290 obs->temperature.emplace(std::stod(cell));
291 }
292 else if (column == "Status")
293 {
294 obs->status = std::bitset<8>{ cell };
295 }
296 else if (column == "SequenceNumber")
297 {
298 obs->sequenceNumber = static_cast<uint8_t>(std::stoul(cell));
299 }
300 }
301 }
302
303 if (!gpsCycle || !gpsWeek || !gpsToW)
304 {
305 LOG_ERROR("{}: Fields 'GpsCycle', 'GpsWeek', 'GpsToW [s]' are needed.", nameId());
306 return nullptr;
307 }
308 if (!accelX || !accelY || !accelZ)
309 {
310 LOG_ERROR("{}: Fields 'AccX [m/s^2]', 'AccY [m/s^2]', 'AccZ [m/s^2]' are needed.", nameId());
311 return nullptr;
312 }
313 if (!gyroX || !gyroY || !gyroZ)
314 {
315 LOG_ERROR("{}: Fields 'GyroX [rad/s]', 'GyroY [rad/s]', 'GyroZ [rad/s]' are needed.", nameId());
316 return nullptr;
317 }
318 obs->insTime = InsTime(gpsCycle.value(), gpsWeek.value(), gpsToW.value());
319 obs->p_acceleration = { accelX.value(), accelY.value(), accelZ.value() };
320 obs->p_angularRate = { gyroX.value(), gyroY.value(), gyroZ.value() };
321
322 if (magX && magY && magZ)
323 {
324 obs->p_magneticField.emplace(magX.value(), magY.value(), magZ.value());
325 }
326 }
327
328 LOG_DATA("DATA({}): {}, {}, {}, {}, {}", name, obs->sequenceNumber, obs->temperature.value(),
329 obs->p_acceleration.x(), obs->p_acceleration.y(), obs->p_acceleration.z());
330
331 // Check if a packet was skipped
333 {
334 if (_prevSequenceNumber == UINT8_MAX)
335 {
336 _prevSequenceNumber = obs->sequenceNumber;
337 }
338 if (obs->sequenceNumber != 0 && (obs->sequenceNumber < _prevSequenceNumber || obs->sequenceNumber > _prevSequenceNumber + 2))
339 {
340 LOG_WARN("{}: Sequence Number changed from {} to {}", name, _prevSequenceNumber, obs->sequenceNumber);
341 }
342 _prevSequenceNumber = obs->sequenceNumber;
343 }
344
346 return obs;
347}
348
350{
351 LOG_TRACE("called for {}", name);
352
353 auto filestream = std::ifstream(getFilepath());
354 if (filestream.good())
355 {
356 union
357 {
358 std::array<char, 4> buffer;
359 uint32_t ui32;
360 } un{};
361
362 if (filestream.readsome(un.buffer.data(), sizeof(uint32_t)) == sizeof(uint32_t))
363 {
364 un.ui32 = uart::stoh(un.ui32, vendor::kvh::KvhUartSensor::ENDIANNESS);
370 {
371 return FileType::BINARY;
372 }
373 }
374
375 filestream.seekg(0, std::ios_base::beg);
376 std::string line;
377 std::getline(filestream, line);
378 filestream.close();
379
380 auto n = std::ranges::count(line, ',');
381
382 if (n >= 3)
383 {
384 return FileType::ASCII;
385 }
386
387 LOG_ERROR("{} could not determine file type", name);
388 return FileType::NONE;
389 }
390
391 LOG_ERROR("{} could not open file {}", name, getFilepath());
392 return FileType::NONE;
393}
Save/Load the Nodes.
nlohmann::json json
json namespace
File Reader for Kvh log files.
Data storage class for one KVH Imu observation.
Helper Functions to work with Kvh Sensors.
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
Definition Logger.hpp:29
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
Definition Logger.hpp:73
#define LOG_WARN
Error occurred, but a fallback option exists and program continues to work normally.
Definition Logger.hpp:71
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Manages all Nodes.
bool initialize()
Initialize the file reader.
void restore(const json &j)
Restores the node from a json object.
std::string _path
Path to the file.
FileType
File Type Enumeration.
@ ASCII
Ascii text data.
@ BINARY
Binary data.
@ NONE
Not specified.
FileType _fileType
File Type.
auto eof() const
Check whether the end of file is reached.
auto & read(char *__s, std::streamsize __n)
Extraction without delimiters.
std::filesystem::path getFilepath()
Returns the path of the file.
@ PATH_CHANGED
The path changed and exists.
std::vector< std::string > _headerColumns
Header Columns of a CSV file.
GuiResult guiConfig(const char *vFilters, const std::vector< std::string > &extensions, size_t id, const std::string &nameId)
ImGui config.
void resetReader()
Moves the read cursor to the start.
auto & getline(std::string &str)
Reads a line from the filestream.
json save() const
Saves the node into a json object.
void deinitialize()
Deinitialize the file reader.
json save() const override
Saves the node into a json object.
Definition Imu.cpp:93
void restore(const json &j) override
Restores the node from a json object.
Definition Imu.cpp:104
void guiConfig() override
ImGui config window which is shown on double click.
Definition Imu.cpp:55
Imu(const Imu &)=delete
Copy constructor.
ImuPos _imuPos
Position and rotation information for conversion from platform to body frame.
Definition Imu.hpp:57
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
static constexpr size_t OUTPUT_PORT_INDEX_KVH_OBS
Flow (KvhObs)
Definition KvhFile.hpp:64
~KvhFile() override
Destructor.
Definition KvhFile.cpp:33
KvhFile()
Default constructor.
Definition KvhFile.cpp:21
static std::string typeStatic()
String representation of the Class Type.
Definition KvhFile.cpp:38
bool resetNode() override
Resets the node. Moves the read cursor to the start.
Definition KvhFile.cpp:156
void deinitialize() override
Deinitialize the node.
Definition KvhFile.cpp:149
uint8_t _prevSequenceNumber
Previous Sequence number to check for order errors.
Definition KvhFile.hpp:85
void restore(const json &j) override
Restores the node from a json object.
Definition KvhFile.cpp:128
static std::string category()
String representation of the Class Category.
Definition KvhFile.cpp:48
vendor::kvh::KvhUartSensor _sensor
Sensor Object.
Definition KvhFile.hpp:82
void guiConfig() override
ImGui config window which is shown on double click.
Definition KvhFile.cpp:53
FileType determineFileType() override
Determines the type of the file.
Definition KvhFile.cpp:349
std::shared_ptr< const NodeData > pollData()
Polls data from the file.
Definition KvhFile.cpp:163
std::string type() const override
String representation of the Class Type.
Definition KvhFile.cpp:43
json save() const override
Saves the node into a json object.
Definition KvhFile.cpp:116
bool initialize() override
Initialize the node.
Definition KvhFile.cpp:142
static std::string type()
Returns the type of the data class.
Definition KvhObs.hpp:39
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
Definition Node.cpp:395
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:410
bool callbacksEnabled
Enables the callbacks.
Definition Node.hpp:402
std::string nameId() const
Node name and id.
Definition Node.cpp:253
std::string name
Name of the Node.
Definition Node.hpp:395
bool doReinitialize(bool wait=false)
Asks the node worker to reinitialize the node.
Definition Node.cpp:350
void invokeCallbacks(size_t portIndex, const std::shared_ptr< const NodeData > &data)
Calls all registered callbacks on the specified output port.
Definition Node.cpp:180
bool _hasConfig
Flag if the config window should be shown.
Definition Node.hpp:413
static constexpr uint32_t HEADER_FMT_XBIT2
Header Format X Bit 2.
static constexpr uint32_t HEADER_FMT_A
Header Format A.
static constexpr uint32_t HEADER_FMT_B
Header Format B.
static constexpr uart::Endianness ENDIANNESS
Endianess of the sensor.
static constexpr uint32_t HEADER_FMT_C
Header Format C.
static constexpr uint32_t HEADER_FMT_XBIT
Header Format X Bit.
OutputPin * CreateOutputPin(Node *node, const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier, OutputPin::PinData data=static_cast< void * >(nullptr), int idx=-1)
Create an Output Pin object.
void ApplyChanges()
Signals that there have been changes to the flow.
void decryptKvhObs(const std::shared_ptr< NAV::KvhObs > &obs)
Decrypts the provided Kvh observation.
@ Flow
NodeData Trigger.
Definition Pin.hpp:52
@ Object
Generic Object.
Definition Pin.hpp:57