|
|
@ -12,15 +12,10 @@ import bisect |
|
|
|
import sys |
|
|
|
import sys |
|
|
|
import ctypes |
|
|
|
import ctypes |
|
|
|
|
|
|
|
|
|
|
|
class Format: |
|
|
|
class Format(object): |
|
|
|
'''Data channel format as specified by the FMT lines in the log file''' |
|
|
|
'''Data channel format as specified by the FMT lines in the log file''' |
|
|
|
NAME = 'FMT' |
|
|
|
|
|
|
|
msgType = 0 |
|
|
|
|
|
|
|
msgLen = 0 |
|
|
|
|
|
|
|
name = "" |
|
|
|
|
|
|
|
types = "" |
|
|
|
|
|
|
|
labels = [] |
|
|
|
|
|
|
|
def __init__(self,msgType,msgLen,name,types,labels): |
|
|
|
def __init__(self,msgType,msgLen,name,types,labels): |
|
|
|
|
|
|
|
self.NAME = 'FMT' |
|
|
|
self.msgType = msgType |
|
|
|
self.msgType = msgType |
|
|
|
self.msgLen = msgLen |
|
|
|
self.msgLen = msgLen |
|
|
|
self.name = name |
|
|
|
self.name = name |
|
|
@ -197,17 +192,15 @@ class BinaryFormat(ctypes.LittleEndianStructure): |
|
|
|
|
|
|
|
|
|
|
|
BinaryFormat.SIZE = ctypes.sizeof(BinaryFormat) |
|
|
|
BinaryFormat.SIZE = ctypes.sizeof(BinaryFormat) |
|
|
|
|
|
|
|
|
|
|
|
class Channel: |
|
|
|
class Channel(object): |
|
|
|
'''storage for a single stream of data, i.e. all GPS.RelAlt values''' |
|
|
|
'''storage for a single stream of data, i.e. all GPS.RelAlt values''' |
|
|
|
|
|
|
|
|
|
|
|
# TODO: rethink data storage, but do more thorough regression testing before refactoring it |
|
|
|
# TODO: rethink data storage, but do more thorough regression testing before refactoring it |
|
|
|
# TODO: store data as a scipy spline curve so we can more easily interpolate and sample the slope? |
|
|
|
# TODO: store data as a scipy spline curve so we can more easily interpolate and sample the slope? |
|
|
|
dictData = None # dict of linenum->value # store dupe data in dict and list for now, until we decide which is the better way to go |
|
|
|
|
|
|
|
listData = None # list of (linenum,value) # store dupe data in dict and list for now, until we decide which is the better way to go |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self): |
|
|
|
def __init__(self): |
|
|
|
self.dictData = {} |
|
|
|
self.dictData = {} # dict of linenum->value # store dupe data in dict and list for now, until we decide which is the better way to go |
|
|
|
self.listData = [] |
|
|
|
self.listData = [] # list of (linenum,value) # store dupe data in dict and list for now, until we decide which is the better way to go |
|
|
|
def getSegment(self, startLine, endLine): |
|
|
|
def getSegment(self, startLine, endLine): |
|
|
|
'''returns a segment of this data (from startLine to endLine, inclusive) as a new Channel instance''' |
|
|
|
'''returns a segment of this data (from startLine to endLine, inclusive) as a new Channel instance''' |
|
|
|
segment = Channel() |
|
|
|
segment = Channel() |
|
|
@ -392,27 +385,35 @@ class DataflashLogHelper: |
|
|
|
return None |
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DataflashLog: |
|
|
|
class DataflashLog(object): |
|
|
|
'''APM Dataflash log file reader and container class. Keep this simple, add more advanced or specific functions to DataflashLogHelper class''' |
|
|
|
'''APM Dataflash log file reader and container class. Keep this simple, add more advanced or specific functions to DataflashLogHelper class''' |
|
|
|
|
|
|
|
|
|
|
|
filename = None |
|
|
|
knownHardwareTypes = ["APM", "PX4", "MPNG"] |
|
|
|
|
|
|
|
intTypes = "bBhHiIM" |
|
|
|
vehicleType = "" # ArduCopter, ArduPlane, ArduRover, etc, verbatim as given by header |
|
|
|
floatTypes = "fcCeEL" |
|
|
|
firmwareVersion = "" |
|
|
|
charTypes = "nNZ" |
|
|
|
firmwareHash = "" |
|
|
|
|
|
|
|
freeRAM = 0 |
|
|
|
def __init__(self, logfile, ignoreBadlines=False): |
|
|
|
hardwareType = "" # APM 1, APM 2, PX4, MPNG, etc What is VRBrain? BeagleBone, etc? Needs more testing |
|
|
|
self.filename = None |
|
|
|
|
|
|
|
|
|
|
|
formats = {} # name -> Format |
|
|
|
self.vehicleType = "" # ArduCopter, ArduPlane, ArduRover, etc, verbatim as given by header |
|
|
|
parameters = {} # token -> value |
|
|
|
self.firmwareVersion = "" |
|
|
|
messages = {} # lineNum -> message |
|
|
|
self.firmwareHash = "" |
|
|
|
modeChanges = {} # lineNum -> (mode,value) |
|
|
|
self.freeRAM = 0 |
|
|
|
channels = {} # lineLabel -> {dataLabel:Channel} |
|
|
|
self.hardwareType = "" # APM 1, APM 2, PX4, MPNG, etc What is VRBrain? BeagleBone, etc? Needs more testing |
|
|
|
|
|
|
|
|
|
|
|
filesizeKB = 0 |
|
|
|
self.formats = {} # name -> Format |
|
|
|
durationSecs = 0 |
|
|
|
self.parameters = {} # token -> value |
|
|
|
lineCount = 0 |
|
|
|
self.messages = {} # lineNum -> message |
|
|
|
skippedLines = 0 |
|
|
|
self.modeChanges = {} # lineNum -> (mode,value) |
|
|
|
|
|
|
|
self.channels = {} # lineLabel -> {dataLabel:Channel} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.filesizeKB = 0 |
|
|
|
|
|
|
|
self.durationSecs = 0 |
|
|
|
|
|
|
|
self.lineCount = 0 |
|
|
|
|
|
|
|
self.skippedLines = 0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.read(logfile, ignoreBadlines) |
|
|
|
|
|
|
|
|
|
|
|
def getCopterType(self): |
|
|
|
def getCopterType(self): |
|
|
|
'''returns quad/hex/octo/tradheli if this is a copter log''' |
|
|
|
'''returns quad/hex/octo/tradheli if this is a copter log''' |
|
|
|