66
77import argparse
88import os
9+ import re
10+
911import numpy as np
1012
1113from .core import ULog
@@ -50,6 +52,16 @@ def main():
5052 args .time_s , args .time_e , args .ignore )
5153
5254
55+ def read_string_data (data : ULog .Data , field_name : str , array_size : int , data_index : int ) -> str :
56+ """ Parse a data field as string """
57+ s = ''
58+ for index in range (array_size ):
59+ character = data .data [f'{ field_name } [{ index } ]' ][data_index ]
60+ if character == 0 :
61+ break
62+ s += chr (character )
63+ return s
64+
5365def convert_ulog2csv (ulog_file_name , messages , output , delimiter , time_s , time_e ,
5466 disable_str_exceptions = False ):
5567 """
@@ -80,17 +92,36 @@ def convert_ulog2csv(ulog_file_name, messages, output, delimiter, time_s, time_e
8092 base_name = os .path .basename (output_file_prefix )
8193 output_file_prefix = os .path .join (output , base_name )
8294
95+ array_pattern = re .compile (r"(.*)\[(.*?)\]" )
96+
97+ def get_fields (data : ULog .Data ) -> tuple [list [str ], dict [str , int ]]:
98+ # use same field order as in the log, except for the timestamp
99+ data_keys = []
100+ string_array_sizes = {}
101+ for f in data .field_data :
102+ if f .field_name .startswith ('_padding' ):
103+ continue
104+ result = array_pattern .fullmatch (f .field_name )
105+ if result and f .type_str == 'char' : # string (array of char's)
106+ field , array_index = result .groups ()
107+ array_index = int (array_index )
108+ string_array_sizes [field ] = max (array_index + 1 , string_array_sizes .get (field , 0 ))
109+ if array_index == 0 :
110+ data_keys .append (field )
111+ else :
112+ data_keys .append (f .field_name )
113+ data_keys .remove ('timestamp' )
114+ data_keys .insert (0 , 'timestamp' ) # we want timestamp at first position
115+ return data_keys , string_array_sizes
116+
83117 for d in data :
84- fmt = '{0}_{1}_{2}.csv'
85- output_file_name = fmt . format ( output_file_prefix , d . name . replace ( '/' , '_' ), d .multi_id )
86- fmt = 'Writing {0} ({1} data points)'
87- # print(fmt.format( output_file_name, len(d. data['timestamp'])) )
118+ name_without_slash = d . name . replace ( '/' , '_' )
119+ output_file_name = f' { output_file_prefix } _ { name_without_slash } _ { d .multi_id } .csv'
120+ num_data_points = len ( d . data [ 'timestamp' ])
121+ print (f'Writing { output_file_name } ( { num_data_points } data points)' )
88122 with open (output_file_name , 'w' , encoding = 'utf-8' ) as csvfile :
89123
90- # use same field order as in the log, except for the timestamp
91- data_keys = [f .field_name for f in d .field_data ]
92- data_keys .remove ('timestamp' )
93- data_keys .insert (0 , 'timestamp' ) # we want timestamp at first position
124+ data_keys , string_array_sizes = get_fields (d )
94125
95126 # we don't use np.savetxt, because we have multiple arrays with
96127 # potentially different data types. However the following is quite
@@ -110,7 +141,11 @@ def convert_ulog2csv(ulog_file_name, messages, output, delimiter, time_s, time_e
110141 last_elem = len (data_keys )- 1
111142 for i in range (time_s_i , time_e_i ):
112143 for k in range (len (data_keys )):
113- csvfile .write (str (d .data [data_keys [k ]][i ]))
144+ if data_keys [k ] in string_array_sizes : # string
145+ s = read_string_data (d , data_keys [k ], string_array_sizes [data_keys [k ]], i )
146+ csvfile .write (s )
147+ else :
148+ csvfile .write (str (d .data [data_keys [k ]][i ]))
114149 if k != last_elem :
115150 csvfile .write (delimiter )
116151 csvfile .write ('\n ' )
0 commit comments