16 std::ifstream replay_file (filename, std::ifstream::in);
18 if (!replay_file.is_open())
20 throw std::runtime_error (
"ULog: Failed to open replay file" );
27 throw std::runtime_error(
"ULog: wrong header");
32 throw std::runtime_error(
"ULog: error loading definitions");
45 replay_file.read(message, message_header.
msg_size);
46 message[message_header.
msg_size] =
'\0';
54 sub.
multi_id = *
reinterpret_cast<uint8_t*
>(message);
55 sub.
msg_id = *
reinterpret_cast<uint16_t*
>( message+1 );
76 uint16_t msg_id = *
reinterpret_cast<uint16_t*
>( message );
82 uint16_t msg_id = *
reinterpret_cast<uint16_t*
>( message );
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 );
116 printf(
"PARAMETER changed at run-time. Ignored\n" );
117 std::cout << std::flush;
125 size_t other_fields_count = 0;
130 if( field.type ==
OTHER)
132 other_fields_count++;
139 sprintf(buff,
".%02d", sub.
multi_id );
140 ts_name += std::string(buff);
151 uint64_t time_val = *
reinterpret_cast<uint64_t*
>(message);
153 message +=
sizeof(uint64_t);
161 char *message,
size_t* index)
163 for (
const auto& field: format->
fields)
166 if (
StringView(field.field_name).starts_with(
"_padding")) {
167 message += field.array_size;
171 for (
int array_pos = 0; array_pos < field.array_size; array_pos++)
177 value =
static_cast<double>( *
reinterpret_cast<uint8_t*
>(message));
181 value =
static_cast<double>( *
reinterpret_cast<int8_t*
>(message));
185 value =
static_cast<double>( *
reinterpret_cast<uint16_t*
>(message));
189 value =
static_cast<double>( *
reinterpret_cast<int16_t*
>(message));
193 value =
static_cast<double>( *
reinterpret_cast<uint32_t*
>(message));
197 value =
static_cast<double>( *
reinterpret_cast<int32_t*
>(message));
201 value =
static_cast<double>( *
reinterpret_cast<uint64_t*
>(message));
205 value =
static_cast<double>( *
reinterpret_cast<int64_t*
>(message));
209 value =
static_cast<double>( *
reinterpret_cast<float*
>(message));
213 value = ( *
reinterpret_cast<double*
>(message));
217 value =
static_cast<double>( *
reinterpret_cast<char*
>(message));
221 value =
static_cast<double>( *
reinterpret_cast<bool*
>(message));
226 auto child_format =
_formats.at( field.other_type_ID );
227 message +=
sizeof(uint64_t);
233 if( field.type !=
OTHER)
235 timeseries.
data[(*index)++].second.push_back( value );
269 file.read(message, msg_size);
270 message[msg_size] = 0;
282 for (
const auto& field: format.
fields)
284 if( field.type ==
OTHER)
290 count += size_t(field.array_size);
298 std::vector<StringView> splitted_strings;
299 splitted_strings.reserve(4);
302 while( pos < strToSplit.size())
304 size_t new_pos = strToSplit.find_first_of(delimeter, pos);
305 if( new_pos == std::string::npos)
307 new_pos = strToSplit.size();
309 StringView sv = { &strToSplit.data()[pos], new_pos - pos };
310 splitted_strings.push_back( sv );
313 return splitted_strings;
323 file.read((
char *)&msg_header,
sizeof(msg_header));
340 return memcmp(magic, msg_header.
magic, 7) == 0;
391 file.seekg(message_header.
msg_size, ios::cur);
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);
408 if (msg_size != 40) {
409 printf(
"unsupported message length for FLAG_BITS message (%i)", msg_size);
415 file.read((
char *)message, msg_size);
418 uint8_t *incompat_flags = message + 8;
422 bool has_unknown_incompat_bits =
false;
424 if (incompat_flags[0] & ~0x1) {
425 has_unknown_incompat_bits =
true;
428 for (
int i = 1;
i < 8; ++
i) {
429 if (incompat_flags[
i]) {
430 has_unknown_incompat_bits =
true;
434 if (has_unknown_incompat_bits) {
435 printf(
"Log contains unknown incompat bits set. Refusing to parse" );
439 if (contains_appended_data)
441 uint64_t appended_offsets[3];
442 memcpy(appended_offsets, message + 16,
sizeof(appended_offsets));
444 if (appended_offsets[0] > 0) {
455 static int count = 0;
459 file.read(buffer, msg_size);
460 buffer[msg_size] = 0;
466 std::string str_format(buffer);
467 size_t pos = str_format.find(
':');
469 if (pos == std::string::npos) {
473 std::string
name = str_format.substr(0, pos);
474 std::string fields = str_format.substr(pos + 1);
478 format.
fields.reserve( fields_split.size() );
479 for (
auto field_section: fields_split)
481 auto field_pair =
splitString( field_section,
' ');
483 auto field_name = field_pair.at(1);
551 while (!helper.ends_with(
"[")) {
552 helper.remove_suffix(1);
555 helper.remove_suffix(1);
588 format.
fields.push_back( field );
598 template<
typename T >
601 std::stringstream stream;
603 << std::setfill (
'0') << std::setw(
sizeof(T)*2)
612 file.read((
char *)message, msg_size);
617 uint8_t key_len = message[0];
619 std::string raw_key((
char *)message, key_len);
624 std::string key = key_parts[1].to_string();
627 if( key_parts[0].starts_with(
"char["))
629 value = std::string( (
char *)message, msg_size - key_len - 1 );
633 bool val = *
reinterpret_cast<const bool*
>(key_parts[0].data());
636 else if( key_parts[0] ==
StringView(
"uint8_t"))
638 uint8_t val = *
reinterpret_cast<const uint8_t*
>(key_parts[0].data());
641 else if( key_parts[0] ==
StringView(
"int8_t"))
643 int8_t val = *
reinterpret_cast<const int8_t*
>(key_parts[0].data());
646 else if( key_parts[0] ==
StringView(
"uint16_t"))
648 uint16_t val = *
reinterpret_cast<const uint16_t*
>(key_parts[0].data());
651 else if( key_parts[0] ==
StringView(
"int16_t"))
653 int16_t val = *
reinterpret_cast<const int16_t*
>(key_parts[0].data());
656 else if( key_parts[0] ==
StringView(
"uint32_t"))
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") )
667 else if( key_parts[0] ==
StringView(
"int32_t"))
669 int32_t val = *
reinterpret_cast<const int32_t*
>(key_parts[0].data());
674 float val = *
reinterpret_cast<const float*
>(key_parts[0].data());
677 else if( key_parts[0] ==
StringView(
"double"))
679 double val = *
reinterpret_cast<const double*
>(key_parts[0].data());
682 else if( key_parts[0] ==
StringView(
"uint64_t"))
684 uint64_t val = *
reinterpret_cast<const uint64_t*
>(key_parts[0].data());
687 else if( key_parts[0] ==
StringView(
"int64_t"))
689 int64_t val = *
reinterpret_cast<const int64_t*
>(key_parts[0].data());
694 _info.insert( { key, value} );
702 file.read((
char *)message, msg_size);
708 uint8_t key_len = message[0];
709 std::string key((
char *)message + 1, key_len);
711 size_t pos = key.find(
' ');
713 if (pos == std::string::npos) {
717 std::string
type = key.substr(0, pos);
720 param.
name = key.substr(pos + 1);
722 if( type ==
"int32_t" )
724 param.
value.
val_int = *
reinterpret_cast<int32_t*
>(message + 1 + key_len);
727 else if( type ==
"float" )
729 param.
value.
val_real = *
reinterpret_cast<float*
>(message + 1 + key_len);
733 throw std::runtime_error(
"unknown parameter type");
743 std::function<void(const Format& format, const std::string& prefix)> appendVector;
747 appendVector = [&appendVector,
this, ×eries](
const Format& format,
const std::string& prefix)
749 for(
const auto& field: format.fields)
752 if (
StringView(field.field_name).starts_with(
"_padding")) {
756 std::string new_prefix = prefix +
"/" + field.field_name;
757 for(
int i=0;
i < field.array_size;
i++)
759 std::string array_suffix =
"";
760 if( field.array_size > 1)
763 sprintf(buff,
".%02d",
i);
766 if( field.type !=
OTHER )
768 timeseries.
data.push_back( {new_prefix + array_suffix, std::vector<double>()} );
771 appendVector( this->
_formats.at( field.other_type_ID ), new_prefix + array_suffix);
777 appendVector(*format, {});
std::vector< uint64_t > timestamps
const std::vector< MessageLog > & getLogs() const
Timeseries createTimeseries(const Format *format)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val)
std::vector< MessageLog > _message_logs
bool readSubscription(std::ifstream &file, uint16_t msg_size)
std::streampos _data_section_start
first ADD_LOGGED_MSG message
bool readParameter(std::ifstream &file, uint16_t msg_size)
#define ULOG_INCOMPAT_FLAG0_DATA_APPENDED_MASK
std::vector< std::pair< std::string, std::vector< double > > > data
uint64_t _file_start_time
std::vector< Parameter > _parameters
std::map< std::string, Timeseries > _timeseries
nonstd::string_view StringView
union ULogParser::Parameter::@4 value
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
const std::map< std::string, Timeseries > & getTimeseriesMap() const
ULogParser(const std::string &filename)
size_t fieldsCount(const Format &format) const
std::map< std::string, std::string > _info
std::string format(const std::string &, const time_point< seconds > &, const femtoseconds &, const time_zone &)
std::map< uint16_t, Subscription > _subscriptions
const std::vector< Parameter > & getParameters() const
#define ULOG_MSG_HEADER_LEN
std::vector< uint8_t > _read_buffer
std::set< std::string > _message_name_with_multi_id
bool readInfo(std::ifstream &file, uint16_t msg_size)
char * parseSimpleDataMessage(Timeseries ×eries, const Format *format, char *message, size_t *index)
std::map< std::string, Format > _formats
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)
bool readFlagBits(std::ifstream &file, uint16_t msg_size)
const std::map< std::string, std::string > & getInfo() const
std::string other_type_ID