diff --git a/Tools/LogAnalyzer/DataflashLog.py b/Tools/LogAnalyzer/DataflashLog.py
index 30c557b1a9..285d463f0d 100644
--- a/Tools/LogAnalyzer/DataflashLog.py
+++ b/Tools/LogAnalyzer/DataflashLog.py
@@ -12,6 +12,8 @@ import bisect
import sys
import ctypes
+from VehicleType import VehicleType, VehicleTypeString
+
class Format(object):
'''Data channel format as specified by the FMT lines in the log file'''
def __init__(self,msgType,msgLen,name,types,labels):
@@ -383,7 +385,7 @@ class DataflashLogHelper:
'''returns an human readable error string if the log is essentially empty, otherwise returns None'''
# naive check for now, see if the throttle output was ever above 20%
throttleThreshold = 20
- if logdata.vehicleType == "ArduCopter":
+ if logdata.vehicleType == VehicleType.Copter:
throttleThreshold = 200 # copter uses 0-1000, plane+rover use 0-100
if "CTUN" in logdata.channels:
maxThrottle = logdata.channels["CTUN"]["ThrOut"].max()
@@ -403,7 +405,8 @@ class DataflashLog(object):
def __init__(self, logfile=None, format="auto", ignoreBadlines=False):
self.filename = None
- self.vehicleType = "" # ArduCopter, ArduPlane, ArduRover, etc, verbatim as given by header
+ self.vehicleType = None # from VehicleType enumeration; value derived from header
+ self.vehicleTypeString = None # set at same time has the enum value
self.firmwareVersion = ""
self.firmwareHash = ""
self.freeRAM = 0
@@ -425,7 +428,7 @@ class DataflashLog(object):
def getCopterType(self):
'''returns quad/hex/octo/tradheli if this is a copter log'''
- if self.vehicleType != "ArduCopter":
+ if self.vehicleType != VehicleType.Copter:
return None
motLabels = []
if "MOT" in self.formats: # not listed in PX4 log header for some reason?
@@ -492,6 +495,22 @@ class DataflashLog(object):
# TODO: calculate logging rate based on timestamps
# ...
+ msg_vehicle_to_vehicle_map = {
+ "ArduCopter": VehicleType.Copter,
+ "APM:Copter": VehicleType.Copter,
+ "ArduPlane": VehicleType.Plane,
+ "ArduRover": VehicleType.Rover
+ }
+
+ # takes the vehicle type supplied via "MSG" and sets vehicleType from
+ # the VehicleType enumeration
+ def set_vehicleType_from_MSG_vehicle(self, MSG_vehicle):
+ ret = self.msg_vehicle_to_vehicle_map.get(MSG_vehicle, None)
+ if ret is None:
+ raise ValueError("Unknown vehicle type (%s)" % (MSG_vehicle))
+ self.vehicleType = ret
+ self.vehicleTypeString = VehicleTypeString[ret]
+
def process(self, lineNumber, e):
if e.NAME == 'FMT':
cls = e.to_class()
@@ -505,15 +524,14 @@ class DataflashLog(object):
elif e.NAME == "MSG":
if not self.vehicleType:
tokens = e.Message.split(' ')
- vehicleTypes = ["ArduPlane", "ArduCopter", "ArduRover"]
- self.vehicleType = tokens[0]
+ self.set_vehicleType_from_MSG_vehicle(tokens[0]);
self.firmwareVersion = tokens[1]
if len(tokens) == 3:
self.firmwareHash = tokens[2][1:-1]
else:
self.messages[lineNumber] = e.Message
elif e.NAME == "MODE":
- if self.vehicleType in ["ArduCopter"]:
+ if self.vehicleType == VehicleType.Copter:
try:
modes = {0:'STABILIZE',
1:'ACRO',
@@ -530,13 +548,21 @@ class DataflashLog(object):
14:'FLIP',
15:'AUTOTUNE',
16:'HYBRID',}
- self.modeChanges[lineNumber] = (modes[int(e.Mode)], e.ThrCrs)
+ if hasattr(e, 'ThrCrs'):
+ self.modeChanges[lineNumber] = (modes[int(e.Mode)], e.ThrCrs)
+ else:
+ # assume it has ModeNum:
+ self.modeChanges[lineNumber] = (modes[int(e.Mode)], e.ModeNum)
except:
- self.modeChanges[lineNumber] = (e.Mode, e.ThrCrs)
- elif self.vehicleType in ["ArduPlane", "APM:Plane", "ArduRover", "APM:Rover", "APM:Copter"]:
+ if hasattr(e, 'ThrCrs'):
+ self.modeChanges[lineNumber] = (e.Mode, e.ThrCrs)
+ else:
+ # assume it has ModeNum:
+ self.modeChanges[lineNumber] = (e.Mode, e.ModeNum)
+ elif self.vehicleType in [VehicleType.Plane, VehicleType.Copter, VehicleType.Rover]:
self.modeChanges[lineNumber] = (e.Mode, e.ModeNum)
else:
- raise Exception("Unknown log type for MODE line vehicletype=({}) linw=({})".format(self.vehicleType, repr(e)))
+ raise Exception("Unknown log type for MODE line vehicletype=({}) linw=({})".format(self.vehicleTypeString, repr(e)))
# anything else must be the log data
else:
groupName = e.NAME
@@ -583,7 +609,7 @@ class DataflashLog(object):
elif tokens2[0] in knownHardwareTypes:
self.hardwareType = line # not sure if we can parse this more usefully, for now only need to report it back verbatim
elif (len(tokens2) == 2 or len(tokens2) == 3) and tokens2[1][0].lower() == "v": # e.g. ArduCopter V3.1 (5c6503e2)
- self.vehicleType = tokens2[0]
+ self.set_vehicleType_from_MSG_vehicle(tokens2[0])
self.firmwareVersion = tokens2[1]
if len(tokens2) == 3:
self.firmwareHash = tokens2[2][1:-1]
diff --git a/Tools/LogAnalyzer/LogAnalyzer.py b/Tools/LogAnalyzer/LogAnalyzer.py
index e87dccbf3e..edf58ad6e9 100755
--- a/Tools/LogAnalyzer/LogAnalyzer.py
+++ b/Tools/LogAnalyzer/LogAnalyzer.py
@@ -30,6 +30,7 @@ import datetime
import time
from xml.sax.saxutils import escape
+from VehicleType import VehicleType
class TestResult(object):
'''all tests return a standardized result type'''
@@ -96,10 +97,10 @@ class TestSuite(object):
print 'Log size: %.2fmb (%d lines)' % (self.logdata.filesizeKB / 1024.0, self.logdata.lineCount)
print 'Log duration: %s' % str(datetime.timedelta(seconds=self.logdata.durationSecs)) + '\n'
- if self.logdata.vehicleType == "ArduCopter" and self.logdata.getCopterType():
- print 'Vehicle Type: %s (%s)' % (self.logdata.vehicleType, self.logdata.getCopterType())
+ if self.logdata.vehicleType == VehicleType.Copter and self.logdata.getCopterType():
+ print 'Vehicle Type: %s (%s)' % (self.logdata.vehicleTypeString, self.logdata.getCopterType())
else:
- print 'Vehicle Type: %s' % self.logdata.vehicleType
+ print 'Vehicle Type: %s' % self.logdata.vehicleTypeString
print 'Firmware Version: %s (%s)' % (self.logdata.firmwareVersion, self.logdata.firmwareHash)
print 'Hardware: %s' % self.logdata.hardwareType
print 'Free RAM: %s' % self.logdata.freeRAM
@@ -158,8 +159,8 @@ class TestSuite(object):
print >>xml, " " + escape(`self.logdata.filesizeKB`) + ""
print >>xml, " " + escape(`self.logdata.lineCount`) + ""
print >>xml, " " + escape(str(datetime.timedelta(seconds=self.logdata.durationSecs))) + ""
- print >>xml, " " + escape(self.logdata.vehicleType) + ""
- if self.logdata.vehicleType == "ArduCopter" and self.logdata.getCopterType():
+ print >>xml, " " + escape(self.logdata.vehicleTypeString) + ""
+ if self.logdata.vehicleType == VehicleType.Copter and self.logdata.getCopterType():
print >>xml, " " + escape(self.logdata.getCopterType()) + ""
print >>xml, " " + escape(self.logdata.firmwareVersion) + ""
print >>xml, " " + escape(self.logdata.firmwareHash) + ""
diff --git a/Tools/LogAnalyzer/UnitTest.py b/Tools/LogAnalyzer/UnitTest.py
index ed97bc66db..29aa0f2a9b 100755
--- a/Tools/LogAnalyzer/UnitTest.py
+++ b/Tools/LogAnalyzer/UnitTest.py
@@ -9,6 +9,7 @@
import DataflashLog
import traceback
+from VehicleType import VehicleType
try:
@@ -16,7 +17,8 @@ try:
logdata = DataflashLog.DataflashLog()
logdata.read("examples/robert_lefebvre_octo_PM.log", ignoreBadlines=False)
assert(logdata.filename == "examples/robert_lefebvre_octo_PM.log")
- assert(logdata.vehicleType == "ArduCopter")
+ assert(logdata.vehicleType == VehicleType.Copter)
+ assert(logdata.vehicleTypeString == "ArduCopter")
assert(logdata.firmwareVersion == "V3.0.1")
assert(logdata.firmwareHash == "5c6503e2")
assert(logdata.freeRAM == 1331)
@@ -38,7 +40,7 @@ try:
assert(logdata.channels['CTUN']['CRate'].listData[3] == (317, 35))
assert(logdata.channels['CTUN']['CRate'].listData[51] == (421, 31))
assert(logdata.channels['CTUN']['CRate'].listData[115] == (563, -8))
- assert(int(logdata.filesizeKB) == 302)
+ assert(int(logdata.filesizeKB) == 307)
assert(logdata.durationSecs == 155)
assert(logdata.lineCount == 4750)
diff --git a/Tools/LogAnalyzer/VehicleType.py b/Tools/LogAnalyzer/VehicleType.py
new file mode 100644
index 0000000000..98fa9fc121
--- /dev/null
+++ b/Tools/LogAnalyzer/VehicleType.py
@@ -0,0 +1,12 @@
+class VehicleType():
+ Plane = 17
+ Copter = 23
+ Rover = 37
+
+# these should really be "Plane", "Copter" and "Rover", but many
+# things use these values as triggers in their code:
+VehicleTypeString = {
+ 17: "ArduPlane",
+ 23: "ArduCopter",
+ 37: "ArduRover"
+}