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


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:18