ulog_parser.cpp
Go to the documentation of this file.
1 #include "ulog_parser.h"
2 #include "ulog_messages.h"
3 
4 #include <fstream>
5 #include <string.h>
6 #include <iosfwd>
7 #include <sstream>
8 #include <iomanip>
9 #include <QDebug>
10 
11 using ios = std::ios;
12 
13 ULogParser::ULogParser(DataStream& datastream) : _file_start_time(0)
14 {
15  bool ret = readFileHeader(datastream);
16 
17  if (!ret)
18  {
19  throw std::runtime_error("ULog: wrong header");
20  }
21 
22  if (!readFileDefinitions(datastream))
23  {
24  throw std::runtime_error("ULog: error loading definitions");
25  }
26 
27  datastream.offset = _data_section_start;
28 
29  while (datastream)
30  {
31  ulog_message_header_s message_header;
32  datastream.read((char*)&message_header, ULOG_MSG_HEADER_LEN);
33 
34  _read_buffer.reserve(message_header.msg_size + 1);
35  char* message = (char*)_read_buffer.data();
36  datastream.read(message, message_header.msg_size);
37  message[message_header.msg_size] = '\0';
38 
39  switch (message_header.msg_type)
40  {
42  Subscription sub;
43 
44  sub.multi_id = *reinterpret_cast<uint8_t*>(message);
45  sub.msg_id = *reinterpret_cast<uint16_t*>(message + 1);
46  message += 3;
47  sub.message_name.assign(message, message_header.msg_size - 3);
48 
49  const auto it = _formats.find(sub.message_name);
50  if (it != _formats.end())
51  {
52  sub.format = &it->second;
53  }
54  _subscriptions.insert({ sub.msg_id, sub });
55 
56  if (sub.multi_id > 0)
57  {
59  }
60 
61  // printf("ADD_LOGGED_MSG: %d %d %s\n", sub.msg_id, sub.multi_id,
62  // sub.message_name.c_str() ); std::cout << std::endl;
63  }
64  break;
66  printf("REMOVE_LOGGED_MSG\n");
67  {
68  uint16_t msg_id = *reinterpret_cast<uint16_t*>(message);
69  _subscriptions.erase(msg_id);
70  }
71  break;
72  case (int)ULogMessageType::DATA: {
73  uint16_t msg_id = *reinterpret_cast<uint16_t*>(message);
74  message += 2;
75  auto sub_it = _subscriptions.find(msg_id);
76  if (sub_it == _subscriptions.end())
77  {
78  continue;
79  }
80  const Subscription& sub = sub_it->second;
81 
82  parseDataMessage(sub, message);
83  }
84  break;
85 
86  case (int)ULogMessageType::LOGGING: {
88  msg.level = static_cast<char>(message[0]);
89  message += sizeof(char);
90  msg.timestamp = *reinterpret_cast<uint64_t*>(message);
91  message += sizeof(uint64_t);
92  msg.msg.assign(message, message_header.msg_size - 9);
93  // printf("LOG %c (%ld): %s\n", msg.level, msg.timestamp, msg.msg.c_str() );
94  _message_logs.push_back(std::move(msg));
95  }
96  break;
97  case (int)ULogMessageType::SYNC: // printf("SYNC\n" );
98  break;
99  case (int)ULogMessageType::DROPOUT: // printf("DROPOUT\n" );
100  break;
101  case (int)ULogMessageType::INFO: // printf("INFO\n" );
102  break;
103  case (int)ULogMessageType::INFO_MULTIPLE: // printf("INFO_MULTIPLE\n" );
104  break;
105  case (int)ULogMessageType::PARAMETER_DEFAULT: // printf("PARAMETER_DEFAULT\n" );
106  break;
107  case (int)ULogMessageType::PARAMETER:
108  printf("PARAMETER changed at run-time. Ignored\n");
109  std::cout << std::flush;
110  break;
111  }
112  }
113 }
114 
116 {
117  size_t other_fields_count = 0;
118  std::string ts_name = sub.message_name;
119 
120  for (const auto& field : sub.format->fields)
121  {
122  if (field.type == OTHER)
123  {
124  other_fields_count++;
125  }
126  }
127 
128  if (_message_name_with_multi_id.count(ts_name) > 0)
129  {
130  char buff[16];
131  sprintf(buff, ".%02d", sub.multi_id);
132  ts_name += std::string(buff);
133  }
134 
135  // get the timeseries or create if if it doesn't exist
136  auto ts_it = _timeseries.find(ts_name);
137  if (ts_it == _timeseries.end())
138  {
139  ts_it = _timeseries.insert({ ts_name, createTimeseries(sub.format) }).first;
140  }
141  Timeseries& timeseries = ts_it->second;
142 
143  uint64_t time_val = *reinterpret_cast<uint64_t*>(message);
144  timeseries.timestamps.push_back(time_val);
145  message += sizeof(uint64_t);
146 
147  size_t index = 0;
148  parseSimpleDataMessage(timeseries, sub.format, message, &index);
149 }
150 
152  char* message, size_t* index)
153 {
154  for (const auto& field : format->fields)
155  {
156  // skip _padding messages which are one byte in size
157  if (StringView(field.field_name).starts_with("_padding"))
158  {
159  message += field.array_size;
160  continue;
161  }
162 
163  for (int array_pos = 0; array_pos < field.array_size; array_pos++)
164  {
165  double value = 0;
166  switch (field.type)
167  {
168  case UINT8: {
169  value = static_cast<double>(*reinterpret_cast<uint8_t*>(message));
170  message += 1;
171  }
172  break;
173  case INT8: {
174  value = static_cast<double>(*reinterpret_cast<int8_t*>(message));
175  message += 1;
176  }
177  break;
178  case UINT16: {
179  value = static_cast<double>(*reinterpret_cast<uint16_t*>(message));
180  message += 2;
181  }
182  break;
183  case INT16: {
184  value = static_cast<double>(*reinterpret_cast<int16_t*>(message));
185  message += 2;
186  }
187  break;
188  case UINT32: {
189  value = static_cast<double>(*reinterpret_cast<uint32_t*>(message));
190  message += 4;
191  }
192  break;
193  case INT32: {
194  value = static_cast<double>(*reinterpret_cast<int32_t*>(message));
195  message += 4;
196  }
197  break;
198  case UINT64: {
199  value = static_cast<double>(*reinterpret_cast<uint64_t*>(message));
200  message += 8;
201  }
202  break;
203  case INT64: {
204  value = static_cast<double>(*reinterpret_cast<int64_t*>(message));
205  message += 8;
206  }
207  break;
208  case FLOAT: {
209  value = static_cast<double>(*reinterpret_cast<float*>(message));
210  message += 4;
211  }
212  break;
213  case DOUBLE: {
214  value = (*reinterpret_cast<double*>(message));
215  message += 8;
216  }
217  break;
218  case CHAR: {
219  value = static_cast<double>(*reinterpret_cast<char*>(message));
220  message += 1;
221  }
222  break;
223  case BOOL: {
224  value = static_cast<double>(*reinterpret_cast<bool*>(message));
225  message += 1;
226  }
227  break;
228  case OTHER: {
229  // recursion!!!
230  auto child_format = _formats.at(field.other_type_ID);
231  message += sizeof(uint64_t); // skip timestamp
232  message = parseSimpleDataMessage(timeseries, &child_format, message, index);
233  }
234  break;
235 
236  } // end switch
237 
238  if (field.type != OTHER)
239  {
240  timeseries.data[(*index)++].second.push_back(value);
241  }
242  } // end for
243  }
244  return message;
245 }
246 
247 const std::map<std::string, ULogParser::Timeseries>& ULogParser::getTimeseriesMap() const
248 {
249  return _timeseries;
250 }
251 
252 const std::vector<ULogParser::Parameter>& ULogParser::getParameters() const
253 {
254  return _parameters;
255 }
256 
257 const std::map<std::string, std::string>& ULogParser::getInfo() const
258 {
259  return _info;
260 }
261 
262 const std::vector<ULogParser::MessageLog>& ULogParser::getLogs() const
263 {
264  return _message_logs;
265 }
266 
267 bool ULogParser::readSubscription(DataStream& datastream, uint16_t msg_size)
268 {
269  _read_buffer.reserve(msg_size + 1);
270  char* message = (char*)_read_buffer.data();
271 
272  datastream.read(message, msg_size);
273  message[msg_size] = 0;
274 
275  if (!datastream)
276  {
277  return false;
278  }
279 
280  return true;
281 }
282 
284 {
285  size_t count = 0;
286  for (const auto& field : format.fields)
287  {
288  if (field.type == OTHER)
289  {
290  // recursion!
291  count += fieldsCount(_formats.at(field.other_type_ID));
292  }
293  else
294  {
295  count += size_t(field.array_size);
296  }
297  }
298  return count;
299 }
300 
301 std::vector<StringView> ULogParser::splitString(const StringView& strToSplit,
302  char delimeter)
303 {
304  std::vector<StringView> splitted_strings;
305  splitted_strings.reserve(4);
306 
307  size_t pos = 0;
308  while (pos < strToSplit.size())
309  {
310  size_t new_pos = strToSplit.find_first_of(delimeter, pos);
311  if (new_pos == std::string::npos)
312  {
313  new_pos = strToSplit.size();
314  }
315  StringView sv = { &strToSplit.data()[pos], new_pos - pos };
316  splitted_strings.push_back(sv);
317  pos = new_pos + 1;
318  }
319  return splitted_strings;
320 }
321 
323 {
324  ulog_file_header_s msg_header;
325  datastream.read((char*)&msg_header, sizeof(msg_header));
326 
327  if (!datastream)
328  {
329  return false;
330  }
331 
332  _file_start_time = msg_header.timestamp;
333 
334  // verify it's an ULog file
335  char magic[8];
336  magic[0] = 'U';
337  magic[1] = 'L';
338  magic[2] = 'o';
339  magic[3] = 'g';
340  magic[4] = 0x01;
341  magic[5] = 0x12;
342  magic[6] = 0x35;
343  return memcmp(magic, msg_header.magic, 7) == 0;
344 }
345 
347 {
348  ulog_message_header_s message_header;
349 
350  while (true)
351  {
352  // qDebug() <<"\noffset before" << datastream.offset;
353  datastream.read((char*)&message_header, ULOG_MSG_HEADER_LEN);
354  // qDebug() <<"msg_size" << message_header.msg_size;
355  // qDebug() <<"type" << char(message_header.msg_type);
356  // qDebug() <<"offset after" << datastream.offset;
357 
358  if (!datastream)
359  {
360  return false;
361  }
362 
363  switch (message_header.msg_type)
364  {
365  case (int)ULogMessageType::FLAG_BITS:
366  if (!readFlagBits(datastream, message_header.msg_size))
367  {
368  return false;
369  }
370  break;
371 
372  case (int)ULogMessageType::FORMAT:
373  if (!readFormat(datastream, message_header.msg_size))
374  {
375  return false;
376  }
377 
378  break;
379 
380  case (int)ULogMessageType::PARAMETER:
381  if (!readParameter(datastream, message_header.msg_size))
382  {
383  return false;
384  }
385 
386  break;
387 
390  return true;
391  }
392 
393  case (int)ULogMessageType::INFO: {
394  if (!readInfo(datastream, message_header.msg_size))
395  {
396  return false;
397  }
398  }
399  break;
400  case (int)ULogMessageType::INFO_MULTIPLE: // skip
401  case (int)ULogMessageType::PARAMETER_DEFAULT: // skip
402  datastream.offset += message_header.msg_size;
403  break;
404 
405  default:
406  printf("unknown log definition type %i, size %i (offset %i)\n",
407  (int)message_header.msg_type, (int)message_header.msg_size,
408  (int)datastream.offset);
409  datastream.offset += message_header.msg_size;
410  break;
411  }
412  }
413  return true;
414 }
415 
416 bool ULogParser::readFlagBits(DataStream& datastream, uint16_t msg_size)
417 {
418  if (msg_size != 40)
419  {
420  printf("unsupported message length for FLAG_BITS message (%i)", msg_size);
421  return false;
422  }
423 
424  _read_buffer.reserve(msg_size);
425  uint8_t* message = (uint8_t*)_read_buffer.data();
426  datastream.read((char*)message, msg_size);
427 
428  // uint8_t *compat_flags = message;
429  uint8_t* incompat_flags = message + 8;
430 
431  // handle & validate the flags
432  bool contains_appended_data =
433  incompat_flags[0] & ULOG_INCOMPAT_FLAG0_DATA_APPENDED_MASK;
434  bool has_unknown_incompat_bits = false;
435 
436  if (incompat_flags[0] & ~0x1)
437  {
438  has_unknown_incompat_bits = true;
439  }
440 
441  for (int i = 1; i < 8; ++i)
442  {
443  if (incompat_flags[i])
444  {
445  has_unknown_incompat_bits = true;
446  }
447  }
448 
449  if (has_unknown_incompat_bits)
450  {
451  printf("Log contains unknown incompat bits set. Refusing to parse");
452  return false;
453  }
454 
455  if (contains_appended_data)
456  {
457  uint64_t appended_offsets[3];
458  memcpy(appended_offsets, message + 16, sizeof(appended_offsets));
459 
460  if (appended_offsets[0] > 0)
461  {
462  // the appended data is currently only used for hardfault dumps, so it's safe to
463  // ignore it.
464  // LOG_INFO("Log contains appended data. Replay will ignore this data" );
465  _read_until_file_position = appended_offsets[0];
466  }
467  }
468  return true;
469 }
470 
471 bool ULogParser::readFormat(DataStream& datastream, uint16_t msg_size)
472 {
473  static int count = 0;
474 
475  _read_buffer.reserve(msg_size + 1);
476  char* buffer = (char*)_read_buffer.data();
477  datastream.read(buffer, msg_size);
478  buffer[msg_size] = 0;
479 
480  if (!datastream)
481  {
482  return false;
483  }
484 
485  std::string str_format(buffer);
486  size_t pos = str_format.find(':');
487 
488  if (pos == std::string::npos)
489  {
490  return false;
491  }
492 
493  std::string name = str_format.substr(0, pos);
494  std::string fields = str_format.substr(pos + 1);
495 
496  Format format;
497  auto fields_split = splitString(fields, ';');
498  format.fields.reserve(fields_split.size());
499  for (auto field_section : fields_split)
500  {
501  auto field_pair = splitString(field_section, ' ');
502  auto field_type = field_pair.at(0);
503  auto field_name = field_pair.at(1);
504 
505  Field field;
506  if (field_type.starts_with("int8_t"))
507  {
508  field.type = INT8;
509  field_type.remove_prefix(6);
510  }
511  else if (field_type.starts_with("int16_t"))
512  {
513  field.type = INT16;
514  field_type.remove_prefix(7);
515  }
516  else if (field_type.starts_with("int32_t"))
517  {
518  field.type = INT32;
519  field_type.remove_prefix(7);
520  }
521  else if (field_type.starts_with("int64_t"))
522  {
523  field.type = INT64;
524  field_type.remove_prefix(7);
525  }
526  else if (field_type.starts_with("uint8_t"))
527  {
528  field.type = UINT8;
529  field_type.remove_prefix(7);
530  }
531  else if (field_type.starts_with("uint16_t"))
532  {
533  field.type = UINT16;
534  field_type.remove_prefix(8);
535  }
536  else if (field_type.starts_with("uint32_t"))
537  {
538  field.type = UINT32;
539  field_type.remove_prefix(8);
540  }
541  else if (field_type.starts_with("uint64_t"))
542  {
543  field.type = UINT64;
544  field_type.remove_prefix(8);
545  }
546  else if (field_type.starts_with("double"))
547  {
548  field.type = DOUBLE;
549  field_type.remove_prefix(6);
550  }
551  else if (field_type.starts_with("float"))
552  {
553  field.type = FLOAT;
554  field_type.remove_prefix(5);
555  }
556  else if (field_type.starts_with("bool"))
557  {
558  field.type = BOOL;
559  field_type.remove_prefix(4);
560  }
561  else if (field_type.starts_with("char"))
562  {
563  field.type = CHAR;
564  field_type.remove_prefix(4);
565  }
566  else
567  {
568  field.type = OTHER;
569 
570  if (field_type.ends_with("]"))
571  {
572  StringView helper = field_type;
573  while (!helper.ends_with("["))
574  {
575  helper.remove_suffix(1);
576  }
577 
578  helper.remove_suffix(1);
579  field.other_type_ID = helper.to_string();
580 
581  while (!field_type.starts_with("["))
582  {
583  field_type.remove_prefix(1);
584  }
585  }
586  else
587  {
588  field.other_type_ID = field_type.to_string();
589  }
590  }
591 
592  field.array_size = 1;
593 
594  if (field_type.size() > 0 && field_type[0] == '[')
595  {
596  field_type.remove_prefix(1);
597  field.array_size = field_type[0] - '0';
598  field_type.remove_prefix(1);
599 
600  while (field_type[0] != ']')
601  {
602  field.array_size = 10 * field.array_size + field_type[0] - '0';
603  field_type.remove_prefix(1);
604  }
605  }
606 
607  if (field.type == UINT64 && field_name == StringView("timestamp"))
608  {
609  // skip
610  }
611  else
612  {
613  field.field_name = field_name.to_string();
614  format.fields.push_back(field);
615  }
616  }
617 
618  format.name = name;
619  _formats[name] = std::move(format);
620 
621  return true;
622 }
623 
624 template <typename T>
625 std::string int_to_hex(T i)
626 {
627  std::stringstream stream;
628  stream << "0x" << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << i;
629  return stream.str();
630 }
631 
632 bool ULogParser::readInfo(DataStream& datastream, uint16_t msg_size)
633 {
634  _read_buffer.reserve(msg_size);
635  uint8_t* message = (uint8_t*)_read_buffer.data();
636  datastream.read((char*)message, msg_size);
637 
638  if (!datastream)
639  {
640  return false;
641  }
642  uint8_t key_len = message[0];
643  message++;
644  std::string raw_key((char*)message, key_len);
645  message += key_len;
646 
647  auto key_parts = splitString(raw_key, ' ');
648 
649  std::string key = key_parts[1].to_string();
650 
651  std::string value;
652  if (key_parts[0].starts_with("char["))
653  {
654  value = std::string((char*)message, msg_size - key_len - 1);
655  }
656  else if (key_parts[0] == StringView("bool"))
657  {
658  bool val = *reinterpret_cast<const bool*>(key_parts[0].data());
659  value = std::to_string(val);
660  }
661  else if (key_parts[0] == StringView("uint8_t"))
662  {
663  uint8_t val = *reinterpret_cast<const uint8_t*>(key_parts[0].data());
664  value = std::to_string(val);
665  }
666  else if (key_parts[0] == StringView("int8_t"))
667  {
668  int8_t val = *reinterpret_cast<const int8_t*>(key_parts[0].data());
669  value = std::to_string(val);
670  }
671  else if (key_parts[0] == StringView("uint16_t"))
672  {
673  uint16_t val = *reinterpret_cast<const uint16_t*>(key_parts[0].data());
674  value = std::to_string(val);
675  }
676  else if (key_parts[0] == StringView("int16_t"))
677  {
678  int16_t val = *reinterpret_cast<const int16_t*>(key_parts[0].data());
679  value = std::to_string(val);
680  }
681  else if (key_parts[0] == StringView("uint32_t"))
682  {
683  uint32_t val = *reinterpret_cast<const uint32_t*>(key_parts[0].data());
684  if (key_parts[1].starts_with("ver_") && key_parts[1].ends_with("_release"))
685  {
686  value = int_to_hex(val);
687  }
688  else
689  {
690  value = std::to_string(val);
691  }
692  }
693  else if (key_parts[0] == StringView("int32_t"))
694  {
695  int32_t val = *reinterpret_cast<const int32_t*>(key_parts[0].data());
696  value = std::to_string(val);
697  }
698  else if (key_parts[0] == StringView("float"))
699  {
700  float val = *reinterpret_cast<const float*>(key_parts[0].data());
701  value = std::to_string(val);
702  }
703  else if (key_parts[0] == StringView("double"))
704  {
705  double val = *reinterpret_cast<const double*>(key_parts[0].data());
706  value = std::to_string(val);
707  }
708  else if (key_parts[0] == StringView("uint64_t"))
709  {
710  uint64_t val = *reinterpret_cast<const uint64_t*>(key_parts[0].data());
711  value = std::to_string(val);
712  }
713  else if (key_parts[0] == StringView("int64_t"))
714  {
715  int64_t val = *reinterpret_cast<const int64_t*>(key_parts[0].data());
716  value = std::to_string(val);
717  }
718 
719  _info.insert({ key, value });
720  return true;
721 }
722 
723 bool ULogParser::readParameter(DataStream& datastream, uint16_t msg_size)
724 {
725  _read_buffer.reserve(msg_size);
726  uint8_t* message = (uint8_t*)_read_buffer.data();
727  datastream.read((char*)message, msg_size);
728 
729  if (!datastream)
730  {
731  return false;
732  }
733 
734  uint8_t key_len = message[0];
735  std::string key((char*)message + 1, key_len);
736 
737  size_t pos = key.find(' ');
738 
739  if (pos == std::string::npos)
740  {
741  return false;
742  }
743 
744  std::string type = key.substr(0, pos);
745 
747  param.name = key.substr(pos + 1);
748 
749  if (type == "int32_t")
750  {
751  param.value.val_int = *reinterpret_cast<int32_t*>(message + 1 + key_len);
752  param.val_type = INT32;
753  }
754  else if (type == "float")
755  {
756  param.value.val_real = *reinterpret_cast<float*>(message + 1 + key_len);
757  param.val_type = FLOAT;
758  }
759  else
760  {
761  throw std::runtime_error("unknown parameter type");
762  }
763  _parameters.push_back(param);
764  return true;
765 }
766 
768 {
769  std::function<void(const Format& format, const std::string& prefix)> appendVector;
770 
771  Timeseries timeseries;
772 
773  appendVector = [&appendVector, this, &timeseries](const Format& format,
774  const std::string& prefix) {
775  for (const auto& field : format.fields)
776  {
777  // skip padding messages
778  if (StringView(field.field_name).starts_with("_padding"))
779  {
780  continue;
781  }
782 
783  std::string new_prefix = prefix + "/" + field.field_name;
784  for (int i = 0; i < field.array_size; i++)
785  {
786  std::string array_suffix = "";
787  if (field.array_size > 1)
788  {
789  char buff[16];
790  sprintf(buff, ".%02d", i);
791  array_suffix = buff;
792  }
793  if (field.type != OTHER)
794  {
795  timeseries.data.push_back({ new_prefix + array_suffix, std::vector<double>() });
796  }
797  else
798  {
799  appendVector(this->_formats.at(field.other_type_ID), new_prefix + array_suffix);
800  }
801  }
802  }
803  };
804 
805  appendVector(*format, {});
806  return timeseries;
807 }
std::vector< uint64_t > timestamps
Definition: ulog_parser.h:109
static int str_format(lua_State *L)
Definition: lstrlib.c:1227
Timeseries createTimeseries(const Format *format)
bool param(const std::string &param_name, T &param_val, const T &default_val)
std::vector< Field > fields
Definition: ulog_parser.h:84
std::vector< MessageLog > _message_logs
Definition: ulog_parser.h:168
const std::map< std::string, std::string > & getInfo() const
std::streampos _data_section_start
first ADD_LOGGED_MSG message
Definition: ulog_parser.h:149
size_t fieldsCount(const Format &format) const
auto printf(const S &fmt, const T &... args) -> int
Definition: printf.h:626
span_CONFIG_SIZE_TYPE size_t
Definition: span.hpp:561
#define ULOG_INCOMPAT_FLAG0_DATA_APPENDED_MASK
const std::map< std::string, Timeseries > & getTimeseriesMap() const
bool readParameter(DataStream &datastream, uint16_t msg_size)
uint64_t _file_start_time
Definition: ulog_parser.h:143
std::vector< Parameter > _parameters
Definition: ulog_parser.h:145
union ULogParser::Parameter::@52 value
std::map< std::string, Timeseries > _timeseries
Definition: ulog_parser.h:162
auto sprintf(const S &fmt, const T &... args) -> std::basic_string< Char >
Definition: printf.h:574
nonstd::string_view StringView
Definition: ulog_parser.h:12
std::string name
Definition: ulog_parser.h:83
const std::vector< Parameter > & getParameters() const
const Format * format
Definition: ulog_parser.h:104
std::ios ios
Definition: ulog_parser.cpp:11
type
Definition: core.h:1059
Definition: core.h:760
std::vector< StringView > splitString(const StringView &strToSplit, char delimeter)
bool readSubscription(DataStream &datastream, uint16_t msg_size)
std::string int_to_hex(T i)
int64_t _read_until_file_position
read limit if log contains appended data
Definition: ulog_parser.h:151
constexpr auto count() -> size_t
Definition: core.h:1050
std::map< std::string, std::string > _info
Definition: ulog_parser.h:158
static void field(LexState *ls, ConsControl *cc)
Definition: lparser.c:891
const std::vector< MessageLog > & getLogs() const
const T & move(const T &v)
Definition: backward.hpp:394
const T & first(const T &value, const Tail &...)
Definition: compile.h:178
#define ULOG_MSG_HEADER_LEN
Definition: ulog_messages.h:65
std::vector< uint8_t > _read_buffer
Definition: ulog_parser.h:147
std::set< std::string > _message_name_with_multi_id
Definition: ulog_parser.h:166
void read(char *dst, int len)
Definition: ulog_parser.h:27
FormatType type
Definition: ulog_parser.h:61
def field_type(f)
ULogParser(DataStream &datastream)
Definition: ulog_parser.cpp:13
char * parseSimpleDataMessage(Timeseries &timeseries, const Format *format, char *message, size_t *index)
bool readInfo(DataStream &datastream, uint16_t msg_size)
bool readFormat(DataStream &datastream, uint16_t msg_size)
std::map< std::string, Format > _formats
Definition: ulog_parser.h:156
Definition: core.h:1131
std::vector< std::pair< std::string, std::vector< double > > > data
Definition: ulog_parser.h:110
void parseDataMessage(const Subscription &sub, char *message)
std::map< uint16_t, Subscription > _subscriptions
Definition: ulog_parser.h:160
bool readFlagBits(DataStream &datastream, uint16_t msg_size)
bool readFileHeader(DataStream &datastream)
bool readFileDefinitions(DataStream &datastream)
std::string field_name
Definition: ulog_parser.h:62
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
Definition: color.h:583
std::string other_type_ID
Definition: ulog_parser.h:63


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:12:53