0.5.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
14
16
18
21{
22 LOG_TRACE("{}: called", name);
23
24 _hasConfig = true;
25 _guiConfigDefaultWindowSize = { 380, 70 };
26
28 CreateOutputPin("Header Columns", Pin::Type::Object, { "std::vector<std::string>" }, &_headerColumns);
29}
30
32{
33 LOG_TRACE("{}: called", nameId());
34}
35
37{
38 return "KvhFile";
39}
40
41std::string NAV::KvhFile::type() const
42{
43 return typeStatic();
44}
45
47{
48 return "Data Provider";
49}
50
52{
53 if (auto res = FileReader::guiConfig(".csv,.*", { ".csv" }, size_t(id), nameId()))
54 {
55 LOG_DEBUG("{}: Path changed to {}", nameId(), _path);
57 if (res == FileReader::PATH_CHANGED)
58 {
60 }
61 else
62 {
64 }
65 }
66
68
70 {
71 // Header info
72 if (ImGui::BeginTable(fmt::format("##VectorNavHeaders ({})", id.AsPointer()).c_str(), 2,
73 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
74 {
75 ImGui::TableSetupColumn("Basic", ImGuiTableColumnFlags_WidthFixed);
76 ImGui::TableSetupColumn("IMU", ImGuiTableColumnFlags_WidthFixed);
77 ImGui::TableHeadersRow();
78
79 auto TextColoredIfExists = [this](int index, const char* displayText, const char* searchText, bool alwaysNormal = false) {
80 ImGui::TableSetColumnIndex(index);
81 if (alwaysNormal || std::ranges::find(_headerColumns, searchText) != _headerColumns.end())
82 {
83 ImGui::TextUnformatted(displayText);
84 }
85 else
86 {
87 ImGui::TextDisabled("%s", displayText);
88 }
89 };
90
91 ImGui::TableNextRow();
92 TextColoredIfExists(0, "GpsTime", "GpsToW [s]");
93 TextColoredIfExists(1, "UnCompMag", "UnCompMagX [Gauss]");
94 ImGui::TableNextRow();
95 TextColoredIfExists(0, "TimeStartup", "TimeStartup [ns]");
96 TextColoredIfExists(1, "UnCompAcc", "UnCompAccX [m/s^2]");
97 ImGui::TableNextRow();
98 TextColoredIfExists(0, "Temperature", "Temperature [Celsius]");
99 TextColoredIfExists(1, "UnCompGyro", "UnCompGyroX [rad/s]");
100 ImGui::TableNextRow();
101 TextColoredIfExists(0, "Status", "Status");
102 ImGui::TableNextRow();
103 TextColoredIfExists(0, "SequenceNumber", "SequenceNumber");
104
105 ImGui::EndTable();
106 }
107 }
108 else if (_fileType == FileType::BINARY)
109 {
110 ImGui::TextUnformatted("Binary file");
111 }
112}
113
114[[nodiscard]] json NAV::KvhFile::save() const
115{
116 LOG_TRACE("{}: called", nameId());
117
118 json j;
119
120 j["FileReader"] = FileReader::save();
121 j["Imu"] = Imu::save();
122
123 return j;
124}
125
127{
128 LOG_TRACE("{}: called", nameId());
129
130 if (j.contains("FileReader"))
131 {
132 FileReader::restore(j.at("FileReader"));
133 }
134 if (j.contains("Imu"))
135 {
136 Imu::restore(j.at("Imu"));
137 }
138}
139
141{
142 LOG_TRACE("{}: called", nameId());
143
144 return FileReader::initialize();
145}
146
148{
149 LOG_TRACE("{}: called", nameId());
150
152}
153
155{
157
158 return true;
159}
160
161std::shared_ptr<const NAV::NodeData> NAV::KvhFile::pollData()
162{
163 std::shared_ptr<KvhObs> obs = nullptr;
164
166 {
167 uint8_t i = 0;
168 std::unique_ptr<uart::protocol::Packet> packet = nullptr;
169 while (!eof() && read(reinterpret_cast<char*>(&i), 1))
170 {
171 packet = _sensor.findPacket(i);
172
173 if (packet != nullptr)
174 {
175 break;
176 }
177 }
178
179 if (!packet)
180 {
181 return nullptr;
182 }
183
184 obs = std::make_shared<KvhObs>(_imuPos, *packet);
185
186 // Check if package is empty
187 if (obs->raw.getRawDataLength() == 0)
188 {
189 return nullptr;
190 }
191
193 }
194 else if (_fileType == FileType::ASCII)
195 {
196 obs = std::make_shared<KvhObs>(_imuPos);
197
198 // Read line
199 std::string line;
200 getline(line);
201 // Remove any starting non text characters
202 line.erase(line.begin(), std::ranges::find_if(line, [](int ch) { return std::isgraph(ch); }));
203
204 if (line.empty())
205 {
206 return nullptr;
207 }
208
209 // Convert line into stream
210 std::stringstream lineStream(line);
211 std::string cell;
212
213 std::optional<uint16_t> gpsCycle = 0;
214 std::optional<uint16_t> gpsWeek;
215 std::optional<long double> gpsToW;
216 std::optional<double> magX;
217 std::optional<double> magY;
218 std::optional<double> magZ;
219 std::optional<double> accelX;
220 std::optional<double> accelY;
221 std::optional<double> accelZ;
222 std::optional<double> gyroX;
223 std::optional<double> gyroY;
224 std::optional<double> gyroZ;
225
226 // Split line at comma
227 for (const auto& column : _headerColumns)
228 {
229 if (std::getline(lineStream, cell, ','))
230 {
231 // Remove any trailing non text characters
232 cell.erase(std::ranges::find_if(cell, [](int ch) { return std::iscntrl(ch); }), cell.end());
233 if (cell.empty())
234 {
235 continue;
236 }
237
238 if (column == "GpsCycle")
239 {
240 gpsCycle = static_cast<uint16_t>(std::stoul(cell));
241 }
242 else if (column == "GpsWeek")
243 {
244 gpsWeek = static_cast<uint16_t>(std::stoul(cell));
245 }
246 else if (column == "GpsToW [s]")
247 {
248 gpsToW = std::stold(cell);
249 }
250 else if (column == "MagX [Gauss]")
251 {
252 magX = std::stod(cell);
253 }
254 else if (column == "MagY [Gauss]")
255 {
256 magY = std::stod(cell);
257 }
258 else if (column == "MagZ [Gauss]")
259 {
260 magZ = std::stod(cell);
261 }
262 else if (column == "AccX [m/s^2]")
263 {
264 accelX = std::stod(cell);
265 }
266 else if (column == "AccY [m/s^2]")
267 {
268 accelY = std::stod(cell);
269 }
270 else if (column == "AccZ [m/s^2]")
271 {
272 accelZ = std::stod(cell);
273 }
274 else if (column == "GyroX [rad/s]")
275 {
276 gyroX = std::stod(cell);
277 }
278 else if (column == "GyroY [rad/s]")
279 {
280 gyroY = std::stod(cell);
281 }
282 else if (column == "GyroZ [rad/s]")
283 {
284 gyroZ = std::stod(cell);
285 }
286 else if (column == "Temperature [Celsius]")
287 {
288 obs->temperature.emplace(std::stod(cell));
289 }
290 else if (column == "Status")
291 {
292 obs->status = std::bitset<8>{ cell };
293 }
294 else if (column == "SequenceNumber")
295 {
296 obs->sequenceNumber = static_cast<uint8_t>(std::stoul(cell));
297 }
298 }
299 }
300
301 if (!gpsCycle || !gpsWeek || !gpsToW)
302 {
303 LOG_ERROR("{}: Fields 'GpsCycle', 'GpsWeek', 'GpsToW [s]' are needed.", nameId());
304 return nullptr;
305 }
306 if (!accelX || !accelY || !accelZ)
307 {
308 LOG_ERROR("{}: Fields 'AccX [m/s^2]', 'AccY [m/s^2]', 'AccZ [m/s^2]' are needed.", nameId());
309 return nullptr;
310 }
311 if (!gyroX || !gyroY || !gyroZ)
312 {
313 LOG_ERROR("{}: Fields 'GyroX [rad/s]', 'GyroY [rad/s]', 'GyroZ [rad/s]' are needed.", nameId());
314 return nullptr;
315 }
316 obs->insTime = InsTime(gpsCycle.value(), gpsWeek.value(), gpsToW.value());
317 obs->p_acceleration = { accelX.value(), accelY.value(), accelZ.value() };
318 obs->p_angularRate = { gyroX.value(), gyroY.value(), gyroZ.value() };
319
320 if (magX && magY && magZ)
321 {
322 obs->p_magneticField.emplace(magX.value(), magY.value(), magZ.value());
323 }
324 }
325
326 LOG_DATA("DATA({}): {}, {}, {}, {}, {}", name, obs->sequenceNumber, obs->temperature.value(),
327 obs->p_acceleration.x(), obs->p_acceleration.y(), obs->p_acceleration.z());
328
329 // Check if a packet was skipped
331 {
332 if (_prevSequenceNumber == UINT8_MAX)
333 {
334 _prevSequenceNumber = obs->sequenceNumber;
335 }
336 if (obs->sequenceNumber != 0 && (obs->sequenceNumber < _prevSequenceNumber || obs->sequenceNumber > _prevSequenceNumber + 2))
337 {
338 LOG_WARN("{}: Sequence Number changed from {} to {}", name, _prevSequenceNumber, obs->sequenceNumber);
339 }
340 _prevSequenceNumber = obs->sequenceNumber;
341 }
342
344 return obs;
345}
346
348{
349 LOG_TRACE("called for {}", name);
350
351 auto filestream = std::ifstream(getFilepath());
352 if (filestream.good())
353 {
354 union
355 {
356 std::array<char, 4> buffer;
357 uint32_t ui32;
358 } un{};
359
360 if (filestream.readsome(un.buffer.data(), sizeof(uint32_t)) == sizeof(uint32_t))
361 {
362 un.ui32 = uart::stoh(un.ui32, vendor::kvh::KvhUartSensor::ENDIANNESS);
368 {
369 return FileType::BINARY;
370 }
371 }
372
373 filestream.seekg(0, std::ios_base::beg);
374 std::string line;
375 std::getline(filestream, line);
376 filestream.close();
377
378 auto n = std::ranges::count(line, ',');
379
380 if (n >= 3)
381 {
382 return FileType::ASCII;
383 }
384
385 LOG_ERROR("{} could not determine file type", name);
386 return FileType::NONE;
387 }
388
389 LOG_ERROR("{} could not open file {}", name, getFilepath());
390 return FileType::NONE;
391}
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
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:31
KvhFile()
Default constructor.
Definition KvhFile.cpp:19
static std::string typeStatic()
String representation of the Class Type.
Definition KvhFile.cpp:36
bool resetNode() override
Resets the node. Moves the read cursor to the start.
Definition KvhFile.cpp:154
void deinitialize() override
Deinitialize the node.
Definition KvhFile.cpp:147
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:126
static std::string category()
String representation of the Class Category.
Definition KvhFile.cpp:46
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:51
FileType determineFileType() override
Determines the type of the file.
Definition KvhFile.cpp:347
std::shared_ptr< const NodeData > pollData()
Polls data from the file.
Definition KvhFile.cpp:161
std::string type() const override
String representation of the Class Type.
Definition KvhFile.cpp:41
json save() const override
Saves the node into a json object.
Definition KvhFile.cpp:114
bool initialize() override
Initialize the node.
Definition KvhFile.cpp:140
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:465
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:522
OutputPin * CreateOutputPin(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.
Definition Node.cpp:278
bool callbacksEnabled
Enables the callbacks.
Definition Node.hpp:514
std::string nameId() const
Node name and id.
Definition Node.cpp:323
std::string name
Name of the Node.
Definition Node.hpp:507
bool doReinitialize(bool wait=false)
Asks the node worker to reinitialize the node.
Definition Node.cpp:420
void invokeCallbacks(size_t portIndex, const std::shared_ptr< const NodeData > &data)
Calls all registered callbacks on the specified output port.
Definition Node.cpp:179
bool _hasConfig
Flag if the config window should be shown.
Definition Node.hpp:525
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.
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