aboutsummaryrefslogtreecommitdiff
path: root/Tools/sdlog2_dump.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/sdlog2_dump.py')
-rw-r--r--Tools/sdlog2_dump.py102
1 files changed, 72 insertions, 30 deletions
diff --git a/Tools/sdlog2_dump.py b/Tools/sdlog2_dump.py
index 318f72971..7fefc5908 100644
--- a/Tools/sdlog2_dump.py
+++ b/Tools/sdlog2_dump.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
-"""Dump binary log generated by sdlog2 or APM as CSV
+from __future__ import print_function
+
+"""Dump binary log generated by PX4's sdlog2 or APM as CSV
Usage: python sdlog2_dump.py <log.bin> [-v] [-e] [-d delimiter] [-n null] [-m MSG[.field1,field2,...]]
@@ -21,6 +23,11 @@ __version__ = "1.2"
import struct, sys
+if sys.hexversion >= 0x030000F0:
+ runningPython3 = True
+else:
+ runningPython3 = False
+
class SDLog2Parser:
BLOCK_SIZE = 8192
MSG_HEADER_LEN = 3
@@ -55,6 +62,8 @@ class SDLog2Parser:
__time_msg = None
__debug_out = False
__correct_errors = False
+ __file_name = None
+ __file = None
def __init__(self):
return
@@ -63,7 +72,7 @@ class SDLog2Parser:
self.__msg_descrs = {} # message descriptions by message type map
self.__msg_labels = {} # message labels by message name map
self.__msg_names = [] # message names in the same order as FORMAT messages
- self.__buffer = "" # buffer for input binary data
+ self.__buffer = bytearray() # buffer for input binary data
self.__ptr = 0 # read pointer in buffer
self.__csv_columns = [] # CSV file columns in correct order in format "MSG.label"
self.__csv_data = {} # current values for all columns
@@ -87,6 +96,14 @@ class SDLog2Parser:
def setCorrectErrors(self, correct_errors):
self.__correct_errors = correct_errors
+
+ def setFileName(self, file_name):
+ self.__file_name = file_name
+ if file_name != None:
+ self.__file = open(file_name, 'w+')
+ else:
+ self.__file = None
+
def process(self, fn):
self.reset()
@@ -95,7 +112,7 @@ class SDLog2Parser:
for msg_name, show_fields in self.__msg_filter:
self.__msg_filter_map[msg_name] = show_fields
first_data_msg = True
- f = open(fn, "r")
+ f = open(fn, "rb")
bytes_read = 0
while True:
chunk = f.read(self.BLOCK_SIZE)
@@ -104,15 +121,15 @@ class SDLog2Parser:
self.__buffer = self.__buffer[self.__ptr:] + chunk
self.__ptr = 0
while self.__bytesLeft() >= self.MSG_HEADER_LEN:
- head1 = ord(self.__buffer[self.__ptr])
- head2 = ord(self.__buffer[self.__ptr+1])
+ head1 = self.__buffer[self.__ptr]
+ head2 = self.__buffer[self.__ptr+1]
if (head1 != self.MSG_HEAD1 or head2 != self.MSG_HEAD2):
if self.__correct_errors:
self.__ptr += 1
continue
else:
raise Exception("Invalid header at %i (0x%X): %02X %02X, must be %02X %02X" % (bytes_read + self.__ptr, bytes_read + self.__ptr, head1, head2, self.MSG_HEAD1, self.MSG_HEAD2))
- msg_type = ord(self.__buffer[self.__ptr+2])
+ msg_type = self.__buffer[self.__ptr+2]
if msg_type == self.MSG_TYPE_FORMAT:
# parse FORMAT message
if self.__bytesLeft() < self.MSG_FORMAT_PACKET_LEN:
@@ -154,10 +171,13 @@ class SDLog2Parser:
show_fields = self.__msg_labels.get(msg_name, [])
self.__msg_filter_map[msg_name] = show_fields
for field in show_fields:
- full_label = msg_name + "." + field
+ full_label = msg_name + "_" + field
self.__csv_columns.append(full_label)
self.__csv_data[full_label] = None
- print self.__csv_delim.join(self.__csv_columns)
+ if self.__file != None:
+ print(self.__csv_delim.join(self.__csv_columns), file=self.__file)
+ else:
+ print(self.__csv_delim.join(self.__csv_columns))
def __printCSVRow(self):
s = []
@@ -168,16 +188,28 @@ class SDLog2Parser:
else:
v = str(v)
s.append(v)
- print self.__csv_delim.join(s)
+
+ if self.__file != None:
+ print(self.__csv_delim.join(s), file=self.__file)
+ else:
+ print(self.__csv_delim.join(s))
def __parseMsgDescr(self):
- data = struct.unpack(self.MSG_FORMAT_STRUCT, self.__buffer[self.__ptr + 3 : self.__ptr + self.MSG_FORMAT_PACKET_LEN])
+ if runningPython3:
+ data = struct.unpack(self.MSG_FORMAT_STRUCT, self.__buffer[self.__ptr + 3 : self.__ptr + self.MSG_FORMAT_PACKET_LEN])
+ else:
+ data = struct.unpack(self.MSG_FORMAT_STRUCT, str(self.__buffer[self.__ptr + 3 : self.__ptr + self.MSG_FORMAT_PACKET_LEN]))
msg_type = data[0]
if msg_type != self.MSG_TYPE_FORMAT:
msg_length = data[1]
- msg_name = data[2].strip("\0")
- msg_format = data[3].strip("\0")
- msg_labels = data[4].strip("\0").split(",")
+ if runningPython3:
+ msg_name = str(data[2], 'ascii').strip("\0")
+ msg_format = str(data[3], 'ascii').strip("\0")
+ msg_labels = str(data[4], 'ascii').strip("\0").split(",")
+ else:
+ msg_name = str(data[2]).strip("\0")
+ msg_format = str(data[3]).strip("\0")
+ msg_labels = str(data[4]).strip("\0").split(",")
# Convert msg_format to struct.unpack format string
msg_struct = ""
msg_mults = []
@@ -194,8 +226,8 @@ class SDLog2Parser:
self.__msg_names.append(msg_name)
if self.__debug_out:
if self.__filterMsg(msg_name) != None:
- print "MSG FORMAT: type = %i, length = %i, name = %s, format = %s, labels = %s, struct = %s, mults = %s" % (
- msg_type, msg_length, msg_name, msg_format, str(msg_labels), msg_struct, msg_mults)
+ print("MSG FORMAT: type = %i, length = %i, name = %s, format = %s, labels = %s, struct = %s, mults = %s" % (
+ msg_type, msg_length, msg_name, msg_format, str(msg_labels), msg_struct, msg_mults))
self.__ptr += self.MSG_FORMAT_PACKET_LEN
def __parseMsg(self, msg_descr):
@@ -205,8 +237,11 @@ class SDLog2Parser:
self.__csv_updated = False
show_fields = self.__filterMsg(msg_name)
if (show_fields != None):
- data = list(struct.unpack(msg_struct, self.__buffer[self.__ptr+self.MSG_HEADER_LEN:self.__ptr+msg_length]))
- for i in xrange(len(data)):
+ if runningPython3:
+ data = list(struct.unpack(msg_struct, self.__buffer[self.__ptr+self.MSG_HEADER_LEN:self.__ptr+msg_length]))
+ else:
+ data = list(struct.unpack(msg_struct, str(self.__buffer[self.__ptr+self.MSG_HEADER_LEN:self.__ptr+msg_length])))
+ for i in range(len(data)):
if type(data[i]) is str:
data[i] = data[i].strip("\0")
m = msg_mults[i]
@@ -214,17 +249,17 @@ class SDLog2Parser:
data[i] = data[i] * m
if self.__debug_out:
s = []
- for i in xrange(len(data)):
+ for i in range(len(data)):
label = msg_labels[i]
if show_fields == "*" or label in show_fields:
s.append(label + "=" + str(data[i]))
- print "MSG %s: %s" % (msg_name, ", ".join(s))
+ print("MSG %s: %s" % (msg_name, ", ".join(s)))
else:
# update CSV data buffer
- for i in xrange(len(data)):
+ for i in range(len(data)):
label = msg_labels[i]
if label in show_fields:
- self.__csv_data[msg_name + "." + label] = data[i]
+ self.__csv_data[msg_name + "_" + label] = data[i]
if self.__time_msg != None and msg_name != self.__time_msg:
self.__csv_updated = True
if self.__time_msg == None:
@@ -233,13 +268,14 @@ class SDLog2Parser:
def _main():
if len(sys.argv) < 2:
- print "Usage: python sdlog2_dump.py <log.bin> [-v] [-e] [-d delimiter] [-n null] [-m MSG[.field1,field2,...]] [-t TIME_MSG_NAME]\n"
- print "\t-v\tUse plain debug output instead of CSV.\n"
- print "\t-e\tRecover from errors.\n"
- print "\t-d\tUse \"delimiter\" in CSV. Default is \",\".\n"
- print "\t-n\tUse \"null\" as placeholder for empty values in CSV. Default is empty.\n"
- print "\t-m MSG[.field1,field2,...]\n\t\tDump only messages of specified type, and only specified fields.\n\t\tMultiple -m options allowed."
- print "\t-t\tSpecify TIME message name to group data messages by time and significantly reduce duplicate output.\n"
+ print("Usage: python sdlog2_dump.py <log.bin> [-v] [-e] [-d delimiter] [-n null] [-m MSG[.field1,field2,...]] [-t TIME_MSG_NAME]\n")
+ print("\t-v\tUse plain debug output instead of CSV.\n")
+ print("\t-e\tRecover from errors.\n")
+ print("\t-d\tUse \"delimiter\" in CSV. Default is \",\".\n")
+ print("\t-n\tUse \"null\" as placeholder for empty values in CSV. Default is empty.\n")
+ print("\t-m MSG[.field1,field2,...]\n\t\tDump only messages of specified type, and only specified fields.\n\t\tMultiple -m options allowed.")
+ print("\t-t\tSpecify TIME message name to group data messages by time and significantly reduce duplicate output.\n")
+ print("\t-fPrint to file instead of stdout")
return
fn = sys.argv[1]
debug_out = False
@@ -247,7 +283,8 @@ def _main():
msg_filter = []
csv_null = ""
csv_delim = ","
- time_msg = None
+ time_msg = "TIME"
+ file_name = None
opt = None
for arg in sys.argv[2:]:
if opt != None:
@@ -257,9 +294,11 @@ def _main():
csv_null = arg
elif opt == "t":
time_msg = arg
+ elif opt == "f":
+ file_name = arg
elif opt == "m":
show_fields = "*"
- a = arg.split(".")
+ a = arg.split("_")
if len(a) > 1:
show_fields = a[1].split(",")
msg_filter.append((a[0], show_fields))
@@ -277,6 +316,8 @@ def _main():
opt = "m"
elif arg == "-t":
opt = "t"
+ elif arg == "-f":
+ opt = "f"
if csv_delim == "\\t":
csv_delim = "\t"
@@ -285,6 +326,7 @@ def _main():
parser.setCSVNull(csv_null)
parser.setMsgFilter(msg_filter)
parser.setTimeMsg(time_msg)
+ parser.setFileName(file_name)
parser.setDebugOut(debug_out)
parser.setCorrectErrors(correct_errors)
parser.process(fn)