delete sdlog2

This commit is contained in:
Daniel Agar
2018-07-12 17:21:18 -04:00
committed by Lorenz Meier
parent 83fd5a5fd1
commit 8537863848
41 changed files with 20 additions and 5042 deletions
+17 -23
View File
@@ -4,30 +4,24 @@
# Standard startup script for logging
#
if param compare SYS_LOGGER 0
set LOGGER_ARGS ""
if param compare SDLOG_MODE 1
then
sdlog2 start -r 100 -a -b 9 -t
else
set LOGGER_ARGS ""
if param compare SDLOG_MODE 1
then
set LOGGER_ARGS "-e"
fi
if param compare SDLOG_MODE 2
then
set LOGGER_ARGS "-f"
fi
if ver hwcmp AEROFC_V1
then
set LOGGER_ARGS "-m mavlink"
fi
logger start -b ${LOGGER_BUF} -t ${LOGGER_ARGS}
unset LOGGER_ARGS
set LOGGER_ARGS "-e"
fi
if param compare SDLOG_MODE 2
then
set LOGGER_ARGS "-f"
fi
if ver hwcmp AEROFC_V1
then
set LOGGER_ARGS "-m mavlink"
fi
logger start -b ${LOGGER_BUF} -t ${LOGGER_ARGS}
unset LOGGER_ARGS
unset LOGGER_BUF
@@ -16,7 +16,6 @@ exec find src platforms \
-path src/lib/matrix -prune -o \
-path src/modules/commander -prune -o \
-path src/modules/micrortps_bridge/micro-CDR -prune -o \
-path src/modules/sdlog2 -prune -o \
-path src/modules/systemlib/uthash -prune -o \
-path src/modules/uavcan/libuavcan -prune -o \
-type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" \) | grep $PATTERN
-29
View File
@@ -1,29 +0,0 @@
====== PX4 LOG CONVERSION ======
On each log session (commonly started and stopped by arming and disarming the vehicle) a new file logxxx.bin is created. In many cases there will be only one logfile named log001.bin (only one flight).
There are two conversion scripts in this ZIP file:
logconv.m: This is a MATLAB script which will automatically convert and display the flight data with a GUI. If running this script, the second script can be ignored.
sdlog2_dump.py: This is a Python script (compatible with v2 and v3) which converts the self-describing binary log format to a CSV file. To export a CSV file from within a shell (Windows CMD or BASH on Linux / Mac OS), run:
```
python sdlog2_dump.py log001.bin -f "export.csv" -t "TIME" -d "," -n ""
```
geo_tag_images.py: Use this script to geotag a set of images. It uses GPS time and file creation date to synchronize the images, so it needs that the images have a valid creation date. Can generate a KML file to view where the photos were taken in Google Earth (including height).
```sh
python geo_tag_images.py --logfile=mylog.bin --input=images/ --output=tagged/ --kml -v
python geo_tag_images.py -l=mylog.bin -i=images/ -o=tagged/ --kml -v
```
geotagging.py: Use this script to geotag a set of images. It uses the CAM trigger data from the log file for image association.
```sh
python geotagging.py --logfile=mylog.bin --input=images/ --output=tagged/
```
Python can be downloaded from http://python.org, but is available as default on Mac OS and Linux.
-434
View File
@@ -1,434 +0,0 @@
#!/usr/bin/env python
#
# Tag the images recorded during a flight with geo location extracted from
# a PX4 binary log file.
#
# This file accepts *.jpg format images and reads position information
# from a *.px4log file
#
# Example Syntax:
# python geo_tag_images.py --logfile=log001.px4log --input=images/ --output=imagesWithTag/ --offset=-0.4 -v
#
# Optional: Correct image times first
# jhead -exonly -ft -n%Y-%m-%d\ %H.%M.%S -ta+HH:MM:SS *.JPG
#
# Author: Hector Azpurua hector@azpurua.com
# Based on the script of Andreas Bircher
import os
import re
import sys
import bisect
import pyexiv2
import argparse
from lxml import etree
import datetime
import calendar
from shutil import copyfile
from subprocess import check_output
from pykml.factory import KML_ElementMaker as KML
from pykml.factory import GX_ElementMaker as GX
class GpsPosition(object):
def __init__(self, timestamp, lat, lon, alt):
self.timestamp = timestamp
self.lat = float(lat)
self.lon = float(lon)
self.alt = float(alt)
class Main:
def __init__(self):
"""
:param logfile:
:param input:
:param output:
:param offset:
:param verbose:
:return:
"""
args = self.get_arg()
self.logfile = args['logfile']
self.input = args['input']
self.output = args['output']
self.kml = args['kml']
self.verbose = args['verbose']
self.offset = args['offset']
self.time_thresh = args['threshold']
self.tdiff_list = []
self.non_processed_files = []
self.tagged_gps = []
print '[INFO] Loading logs and images locations...'
self.gps_list = self.load_gps_from_log(self.logfile, self.offset)
self.img_list = self.load_image_list(self.input)
if len(self.img_list) <= 0:
print '[ERROR] Cannot load JPG images from input folder, please check filename extensions.'
sys.exit(1)
if not os.path.exists(self.output):
os.makedirs(self.output)
if not self.output.endswith(os.path.sep):
self.output += os.path.sep
self.tag_images()
if self.kml and len(self.tdiff_list) > 0:
self.gen_kml()
if len(self.non_processed_files) > 0:
print '[WARNING] Some images werent processed (', len(self.non_processed_files), 'of', len(self.img_list), '):'
for elem in self.non_processed_files:
print '\t', elem
@staticmethod
def to_degree(value, loc):
"""
Convert a lat or lon value to degrees/minutes/seconds
:param value: the latitude or longitude value
:param loc: could be ["S", "N"] or ["W", "E"]
:return:
"""
if value < 0:
loc_value = loc[0]
elif value > 0:
loc_value = loc[1]
else:
loc_value = ""
absolute_value = abs(value)
deg = int(absolute_value)
t1 = (absolute_value - deg) * 60
minute = int(t1)
sec = round((t1 - minute) * 60, 5)
return deg, minute, sec, loc_value
@staticmethod
def gps_week_seconds_to_datetime(gpsweek, gpsmillis, leapmillis=0):
"""
Convert GPS week and seconds to datetime object, using leap milliseconds if necessary
:param gpsweek:
:param gpsmillis:
:param leapmillis:
:return:
"""
datetimeformat = "%Y-%m-%d %H:%M:%S.%f"
epoch = datetime.datetime.strptime(
"1980-01-06 00:00:00.000", datetimeformat)
elapsed = datetime.timedelta(
days=(gpsweek * 7), milliseconds=(gpsmillis + leapmillis))
return Main.utc_to_local(epoch + elapsed)
@staticmethod
def unix_microseconds_to_datetime(unix_us, offset=0):
"""
Convert unix microseconds to datetime object, using offset milliseconds if necessary
:param unix_us:
:param offset:
:return:
"""
# time in seconds
time_s = int(unix_us) / 1000000 + (offset / 1000)
datetime_from_unix = datetime.datetime.fromtimestamp(time_s)
return datetime_from_unix
@staticmethod
def utc_to_local(utc_dt):
"""
Convert UTC time in local time
:param utc_dt:
:return:
"""
# use integer timestamp to avoid precision loss
timestamp = calendar.timegm(utc_dt.timetuple())
local_dt = datetime.datetime.fromtimestamp(timestamp)
assert utc_dt.resolution >= datetime.timedelta(microseconds=1)
return local_dt.replace(microsecond=utc_dt.microsecond)
def gen_kml(self):
"""
Generate a KML file with keypoints on the locations of the pictures, including height
:return:
"""
style_dot = "sn_shaded_dot"
style_path = "red_path"
doc = KML.kml(
KML.Document(
KML.Name("GPS of the images"),
KML.Style(
KML.IconStyle(
KML.scale(0.4),
KML.Icon(
KML.href(
"http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png")
),
),
id=style_dot,
),
KML.Style(
KML.LineStyle(
KML.color('7f0000ff'),
KML.width(6),
GX.labelVisibility('1'),
),
id=style_path
)
)
)
# create points
for i, gps in enumerate(self.tagged_gps):
ii = i + 1
doc.Document.append(
KML.Placemark(
KML.styleUrl('#{0}'.format(style_dot)),
KML.Point(
KML.extrude(True),
KML.altitudeMode('absolute'),
KML.coordinates(
"{},{},{}".format(gps.lon, gps.lat, gps.alt))
),
KML.name(
str(ii)) if ii % 5 == 0 or ii == 1 else KML.name()
)
)
# create the path
doc.Document.append(
KML.Placemark(
KML.styleUrl('#{0}'.format(style_path)),
KML.LineString(
KML.altitudeMode('absolute'),
KML.coordinates(
' '.join(["{},{},{}".format(gps.lon, gps.lat, gps.alt)
for gps in self.tagged_gps])
)
)
)
)
s = etree.tostring(doc)
file_path = self.output + 'GoogleEarth_points.kml'
f = open(file_path, 'w')
f.write(s)
f.close()
print '[INFO] KML file generated on:', file_path
def get_closest_datetime_index(self, datetime_list, elem):
"""
Get the closest element between a list of datetime objects and a date
:param datetime_list:
:param elem:
:return:
"""
dlist_len = len(datetime_list)
i = bisect.bisect_left(datetime_list, elem)
# Cleanup of the indices
if i < 0:
i = 0
elif i >= dlist_len:
i = dlist_len - 1
date = datetime_list[i]
diff = abs((date - elem).total_seconds())
if diff > self.time_thresh:
return -1, diff
return i, diff
def set_gps_location(self, file_name, lat, lng, alt):
"""
Add the GPS tag and altitude to a image file
:param file_name:
:param lat:
:param lng:
:param alt:
:return:
"""
lat_deg = self.to_degree(lat, ["S", "N"])
lng_deg = self.to_degree(lng, ["W", "E"])
exiv_lat = (pyexiv2.Rational(lat_deg[0] * 60 + lat_deg[1], 60),
pyexiv2.Rational(lat_deg[2] * 100, 6000), pyexiv2.Rational(0, 1))
exiv_lng = (pyexiv2.Rational(lng_deg[0] * 60 + lng_deg[1], 60),
pyexiv2.Rational(lng_deg[2] * 100, 6000), pyexiv2.Rational(0, 1))
try:
exiv_image = pyexiv2.ImageMetadata(file_name)
exiv_image.read()
exiv_image["Exif.GPSInfo.GPSLatitude"] = exiv_lat
exiv_image["Exif.GPSInfo.GPSLatitudeRef"] = lat_deg[3]
exiv_image["Exif.GPSInfo.GPSLongitude"] = exiv_lng
exiv_image["Exif.GPSInfo.GPSLongitudeRef"] = lng_deg[3]
exiv_image["Exif.GPSInfo.GPSAltitude"] = pyexiv2.Rational(alt, 1)
exiv_image["Exif.GPSInfo.GPSAltitudeRef"] = '0'
exiv_image["Exif.Image.GPSTag"] = 654
exiv_image["Exif.GPSInfo.GPSMapDatum"] = "WGS-84"
exiv_image["Exif.GPSInfo.GPSVersionID"] = '2 0 0 0'
exiv_image.write(True)
except Exception as e:
print '[ERROR]', e
def load_gps_from_log(self, log_file, offset):
"""
Load gps list from PX4 binary log
:param log_file:
:param offset:
:return:
"""
gps_list = []
out = check_output(
["python", "sdlog2_dump.py", log_file, "-m GPS", "-v"])
for line in out.splitlines():
if not line.startswith("MSG GPS:"):
continue
vdict = {}
pairs = re.split(r'[;,:]\s*', line)
for pair in pairs:
e = pair.split('=')
if len(e) == 2:
vdict[e[0]] = float(e[1])
# PX4 GPS.GPSTime is unix time in microseconds
gps_time = vdict['GPSTime']
gps_lat = vdict['Lat']
gps_lon = vdict['Lon']
gps_alt = vdict['Alt']
date = self.unix_microseconds_to_datetime(gps_time, offset)
gps_list.append(GpsPosition(date, gps_lat, gps_lon, gps_alt))
return gps_list
def get_image_creation_date(self, filename):
exiv_image = pyexiv2.ImageMetadata(filename)
exiv_image.read()
# Prefer DateTime/Original over the other values
if 'Exif.Photo.DateTimeOriginal' in exiv_image:
cdate = exiv_image['Exif.Photo.DateTimeOriginal'].value
return cdate
elif 'Exif.Image.DateTime' in exiv_image:
cdate = exiv_image['Exif.Image.DateTime'].value
return cdate
else:
epoch = os.path.getmtime(filename)
return datetime.datetime.fromtimestamp(epoch)
def load_image_list(self, input_folder, file_type='jpg'):
"""
Load image list from a folder given a file type
:param input_folder:
:param file_type:
:return:
"""
self.img_list = [input_folder + filename for filename in os.listdir(input_folder)
if re.search(r'\.' + file_type + '$', filename, re.IGNORECASE)]
self.img_list = sorted(self.img_list)
return self.img_list
def tag_images(self):
"""
Tag the image list using the GPS loaded from the LOG file
:return:
"""
tagged_gps = []
img_size = len(self.img_list)
print '[INFO] Number of images:', img_size
print '[INFO] Number of gps logs:', len(self.gps_list)
dt_list = [x.timestamp for x in self.gps_list]
img_seq = 1
for i in xrange(img_size):
cdate = self.get_image_creation_date(self.img_list[i])
gps_i, img_tdiff = self.get_closest_datetime_index(dt_list, cdate)
base_path, filename = os.path.split(self.img_list[i])
if gps_i == -1:
self.non_processed_files.append(filename)
continue
closest_gps = self.gps_list[gps_i]
self.tdiff_list.append(img_tdiff)
if self.verbose:
msg = "[DEBUG] %s/%s) %s\n\timg %s -> gps %s (%ss)\n\tlat:%s, lon:%s, alt:%s".ljust(60) %\
(i + 1, img_size, filename, cdate, closest_gps.timestamp,
img_tdiff, closest_gps.lat, closest_gps.lon, closest_gps.alt)
print msg
output_filename = self.output + str(img_seq) + '_' + filename
copyfile(self.img_list[i], output_filename)
self.set_gps_location(
output_filename, closest_gps.lat, closest_gps.lon, closest_gps.alt)
self.tagged_gps.append(closest_gps)
img_seq += 1
if len(self.tdiff_list) > 0:
print '[INFO] Mean diff in seconds:', sum(self.tdiff_list) / float(len(self.tdiff_list))
@staticmethod
def get_arg():
parser = argparse.ArgumentParser(
description='Geotag script to add GPS info to pictures from PX4 binary log files.'
'It uses synchronized time to allocate GPS positions.'
)
parser.add_argument(
'-l', '--logfile', help='PX4 log file containing recorded positions.', required=True
)
parser.add_argument(
'-i', '--input', help='Input folder containing untagged images.', required=True
)
parser.add_argument(
'-o', '--output', help='Output folder to contain tagged images.', required=True
)
parser.add_argument(
'-t', '--threshold', help='Time threshold between the GPS time and the local image time.',
default=1, required=False, type=float
)
parser.add_argument(
'-of', '--offset', help='Time offset in MILLISECONDS between the GPS time and the local time.',
default=0, required=False, type=float
)
parser.add_argument(
'-kml', '--kml', help='Save the in KML format the information of all tagged images.',
required=False, action='store_true'
)
parser.add_argument(
'-v', '--verbose', help='Prints lots of information.',
required=False, action='store_true'
)
args = vars(parser.parse_args())
return args
if __name__ == "__main__":
m = Main()
-237
View File
@@ -1,237 +0,0 @@
#!/usr/bin/env python
#
# __geotagging__
# Tag the images recorded during a flight with geo location extracted from
# a PX4 log file.
#
# This file accepts *.jpg format images and reads position information
# from a *.px4log file
#
# Example Syntax:
# python geotagging.py --logfile=log001.px4log --input=images/
# --output=imagesWithTag/
#
# Author: Andreas Bircher, Wingtra, http://wingtra.com, in 2016
#
import glob
import os
import pyexiv2
from shutil import copyfile
from optparse import OptionParser
import csv
from datetime import datetime, timedelta
class TriggerList(object):
def __init__(self):
self.CAMT_seq = []
self.CAMT_timestamp = []
self.GPOS_Lat = []
self.GPOS_Lon = []
self.GPOS_Alt = []
self.GPS_GPSTime = []
class ImageList(object):
def __init__(self):
self.jpg = []
self.raw = []
def to_degree(value, loc):
if value < 0:
loc_value = loc[0]
elif value > 0:
loc_value = loc[1]
else:
loc_value = ""
absolute_value = abs(value)
deg = int(absolute_value)
t1 = (absolute_value - deg) * 60
min = int(t1)
sec = round((t1 - min) * 60, 5)
return (deg, min, sec, loc_value)
def SetGpsLocation(file_name, gps_datetime, lat, lng, alt):
"""
Adding GPS tag
"""
lat_deg = to_degree(lat, ["S", "N"])
lng_deg = to_degree(lng, ["W", "E"])
exiv_lat = (pyexiv2.Rational(lat_deg[0] * 60 + lat_deg[1], 60), pyexiv2.Rational(
lat_deg[2] * 100, 6000), pyexiv2.Rational(0, 1))
exiv_lng = (pyexiv2.Rational(lng_deg[0] * 60 + lng_deg[1], 60), pyexiv2.Rational(
lng_deg[2] * 100, 6000), pyexiv2.Rational(0, 1))
exiv_image = pyexiv2.ImageMetadata(file_name)
exiv_image.read()
date_tag = exiv_image['Exif.Image.DateTime']
date_max = max(date_tag.value, gps_datetime)
date_min = min(date_tag.value, gps_datetime)
time_diff = date_max - date_min
if (time_diff > timedelta(seconds=5)):
print(
"WARNING, camera trigger and photo time different by {}".format(time_diff))
print(" Photo tag time: {}".format(date_tag.value))
print(" Camera trigger time: {}".format(gps_datetime))
exiv_image["Exif.GPSInfo.GPSLatitude"] = exiv_lat
exiv_image["Exif.GPSInfo.GPSLatitudeRef"] = lat_deg[3]
exiv_image["Exif.GPSInfo.GPSLongitude"] = exiv_lng
exiv_image["Exif.GPSInfo.GPSLongitudeRef"] = lng_deg[3]
exiv_image["Exif.GPSInfo.GPSAltitude"] = pyexiv2.Rational(alt, 1)
exiv_image["Exif.GPSInfo.GPSAltitudeRef"] = '0'
exiv_image["Exif.Image.GPSTag"] = 654
exiv_image["Exif.GPSInfo.GPSMapDatum"] = "WGS-84"
exiv_image["Exif.GPSInfo.GPSVersionID"] = '2 0 0 0'
exiv_image.write(True)
def LoadPX4log(px4_log_file):
"""
load px4 log file and extract trigger locations
"""
os.system('python sdlog2_dump.py ' + px4_log_file +
' -t time -m TIME -m CAMT -m GPOS -m GPS -f log.csv')
f = open('log.csv', 'rb')
reader = csv.reader(f)
headers = reader.next()
line = {}
for h in headers:
line[h] = []
for row in reader:
for h, v in zip(headers, row):
line[h].append(v)
trigger_list = TriggerList()
for seq in range(0, len(line['CAMT_seq']) - 1):
if line['CAMT_seq'][seq] != line['CAMT_seq'][seq + 1]:
trigger_list.CAMT_seq.append(line['CAMT_seq'][seq + 1])
trigger_list.CAMT_timestamp.append(line['CAMT_timestamp'][seq + 1])
trigger_list.GPOS_Lat.append(line['GPOS_Lat'][seq + 1])
trigger_list.GPOS_Lon.append(line['GPOS_Lon'][seq + 1])
trigger_list.GPOS_Alt.append(line['GPOS_Alt'][seq + 1])
trigger_list.GPS_GPSTime.append(line['GPS_GPSTime'][seq + 1])
return trigger_list
def LoadImageList(input_folder):
"""
load the image list
"""
image_list = ImageList()
for jpg_image in glob.glob(input_folder + "/*.jpg"):
image_list.jpg.append(jpg_image)
for jpg_image in glob.glob(input_folder + "/*.JPG"):
image_list.jpg.append(jpg_image)
for raw_image in glob.glob(input_folder + "/*.RC"):
image_list.raw.append(raw_image)
if len(image_list.jpg) != len(image_list.raw) and len(image_list.jpg) * len(image_list.raw) != 0:
print("Unequal number of jpg and raw images")
if len(image_list.jpg) == 0 and len(image_list.raw) == 0:
print("No images found")
image_list.jpg = sorted(image_list.jpg)
image_list.raw = sorted(image_list.raw)
return image_list
def FilterTrigger(trigger_list, image_list):
"""
filter triggers to allow exact matching with recorded images
"""
# filter trigger list to match the number of pics
if len(image_list.jpg) != len(trigger_list.CAMT_seq):
print('WARNING! differ number of jpg images ({}) and camera triggers ({})'.format(
len(image_list.jpg), len(trigger_list.CAMT_seq)))
n_overlap = min(len(image_list.jpg), len(trigger_list.CAMT_seq))
del image_list.jpg[n_overlap:]
if len(image_list.raw) != len(trigger_list.CAMT_seq):
print('WARNING! differ number of raw images ({}) and camera triggers ({})'.format(
len(image_list.raw), len(trigger_list.CAMT_seq)))
n_overlap = min(len(image_list.raw), len(trigger_list.CAMT_seq))
del image_list.raw[n_overlap:]
return trigger_list
def TagImages(trigger_list, image_list, output_folder):
"""
load px4 log file and extract trigger locations
"""
for image in range(len(image_list.jpg)):
print("############################################################")
print('Photo {}: {}'.format(image, image_list.jpg[image]))
cam_time = int(trigger_list.GPS_GPSTime[image]) / 1000000
gps_datetime = datetime.fromtimestamp(cam_time)
base_path, filename = os.path.split(image_list.jpg[image])
copyfile(image_list.jpg[image], output_folder + "/" + filename)
SetGpsLocation(output_folder + "/" + filename, gps_datetime, float(
trigger_list.GPOS_Lat[image]), float(trigger_list.GPOS_Lon[image]), float(trigger_list.GPOS_Alt[image]))
for image in range(len(image_list.raw)):
print("############################################################")
print('Photo {}: {}'.format(image, image_list.raw[image]))
cam_time = int(trigger_list.GPS_GPSTime[image]) / 1000000
gps_datetime = datetime.fromtimestamp(cam_time)
base_path, filename = os.path.split(image_list.raw[image])
copyfile(image_list.raw[image], output_folder + "/" + filename)
SetGpsLocation(output_folder + "/" + filename, gps_datetime, float(
trigger_list.GPOS_Lat[image]), float(trigger_list.GPOS_Lon[image]), float(trigger_list.GPOS_Alt[image]))
def main():
"""
Main method
"""
parser = OptionParser()
parser.add_option("-l", "--logfile", dest="LogFile",
help="PX4 log file containing recorded positions",
metavar="string")
parser.add_option("-i", "--input", dest="InputFolder",
help="Input folder containing untagged images in alphabetical order",
type="string")
parser.add_option("-o", "--output", dest="OutputFolder",
help="Output folder to contain tagged images",
type="string")
(options, args) = parser.parse_args()
if not options.LogFile:
print "please type python " \
"geotagging.py --logfile=[filename] --intput=[folder] [--output=[folder]]"
elif not options.InputFolder:
print "please type python " \
"geotagging.py --logfile=[filename] --intput=[folder] [--output=[folder]]s"
else:
trigger_list = LoadPX4log(options.LogFile)
image_list = LoadImageList(options.InputFolder)
if not options.OutputFolder:
options.OutputFolder = "imagesWithTag"
if not os.path.exists(options.OutputFolder):
os.makedirs(options.OutputFolder)
trigger_list = FilterTrigger(trigger_list, image_list)
TagImages(trigger_list, image_list, options.OutputFolder)
if __name__ == "__main__":
main()
File diff suppressed because it is too large Load Diff
-343
View File
@@ -1,343 +0,0 @@
#!/usr/bin/env python
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,...]]
Example Usage: python sdlog2_dump.py log.bin -m GPS_Lat,Lng -m AHR2_Roll,Pitch,Yaw
-v Use plain debug output instead of CSV.
-e Recover from errors.
-d Use "delimiter" in CSV. Default is ",".
-n Use "null" as placeholder for empty values in CSV. Default is empty.
-m MSG[_field1,field2,...]
Dump only messages of specified type, and only specified fields.
Multiple -m options allowed.
"""
__author__ = "Anton Babushkin"
__version__ = "1.2"
import struct, sys
if sys.hexversion >= 0x030000F0:
runningPython3 = True
def _parseCString(cstr):
return str(cstr, 'ascii').split('\0')[0]
else:
runningPython3 = False
def _parseCString(cstr):
return str(cstr).split('\0')[0]
class SDLog2Parser:
BLOCK_SIZE = 8192
MSG_HEADER_LEN = 3
MSG_HEAD1 = 0xA3
MSG_HEAD2 = 0x95
MSG_FORMAT_PACKET_LEN = 89
MSG_FORMAT_STRUCT = "BB4s16s64s"
MSG_TYPE_FORMAT = 0x80
FORMAT_TO_STRUCT = {
"b": ("b", None),
"B": ("B", None),
"h": ("h", None),
"H": ("H", None),
"i": ("i", None),
"I": ("I", None),
"f": ("f", None),
"d": ("d", None),
"n": ("4s", None),
"N": ("16s", None),
"Z": ("64s", None),
"c": ("h", 0.01),
"C": ("H", 0.01),
"e": ("i", 0.01),
"E": ("I", 0.01),
"L": ("i", 0.0000001),
"M": ("b", None),
"q": ("q", None),
"Q": ("Q", None),
}
__csv_delim = ","
__csv_null = ""
__msg_filter = []
__time_msg = None
__debug_out = False
__correct_errors = False
__file_name = None
__file = None
def __init__(self):
return
def reset(self):
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 = 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
self.__csv_updated = False
self.__msg_filter_map = {} # filter in form of map, with '*" expanded to full list of fields
def setCSVDelimiter(self, csv_delim):
self.__csv_delim = csv_delim
def setCSVNull(self, csv_null):
self.__csv_null = csv_null
def setMsgFilter(self, msg_filter):
self.__msg_filter = msg_filter
def setTimeMsg(self, time_msg):
self.__time_msg = time_msg
def setDebugOut(self, debug_out):
self.__debug_out = debug_out
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()
if self.__debug_out:
# init __msg_filter_map
for msg_name, show_fields in self.__msg_filter:
self.__msg_filter_map[msg_name] = show_fields
first_data_msg = True
f = open(fn, "rb")
bytes_read = 0
while True:
chunk = f.read(self.BLOCK_SIZE)
if len(chunk) == 0:
break
self.__buffer = self.__buffer[self.__ptr:] + chunk
self.__ptr = 0
while self.__bytesLeft() >= self.MSG_HEADER_LEN:
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 = self.__buffer[self.__ptr+2]
if msg_type == self.MSG_TYPE_FORMAT:
# parse FORMAT message
if self.__bytesLeft() < self.MSG_FORMAT_PACKET_LEN:
break
self.__parseMsgDescr()
else:
# parse data message
msg_descr = self.__msg_descrs.get(msg_type, None)
if msg_descr == None:
if self.__correct_errors:
self.__ptr += 1
continue
else:
raise Exception("Unknown msg type: %i" % msg_type)
msg_length = msg_descr[0]
if self.__bytesLeft() < msg_length:
break
if first_data_msg:
# build CSV columns and init data map
if not self.__debug_out:
self.__initCSV()
first_data_msg = False
self.__parseMsg(msg_descr)
bytes_read += self.__ptr
if not self.__debug_out and self.__time_msg != None and self.__csv_updated:
self.__printCSVRow()
f.close()
def __bytesLeft(self):
return len(self.__buffer) - self.__ptr
def __filterMsg(self, msg_name):
show_fields = "*"
if len(self.__msg_filter_map) > 0:
show_fields = self.__msg_filter_map.get(msg_name)
return show_fields
def __initCSV(self):
if len(self.__msg_filter) == 0:
for msg_name in self.__msg_names:
self.__msg_filter.append((msg_name, "*"))
for msg_name, show_fields in self.__msg_filter:
if show_fields == "*":
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
self.__csv_columns.append(full_label)
self.__csv_data[full_label] = None
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 = []
for full_label in self.__csv_columns:
v = self.__csv_data[full_label]
if v == None:
v = self.__csv_null
else:
v = str(v)
s.append(v)
if self.__file != None:
print(self.__csv_delim.join(s), file=self.__file)
else:
print(self.__csv_delim.join(s))
def __parseMsgDescr(self):
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 = _parseCString(data[2])
msg_format = _parseCString(data[3])
msg_labels = _parseCString(data[4]).split(",")
# Convert msg_format to struct.unpack format string
msg_struct = ""
msg_mults = []
for c in msg_format:
try:
f = self.FORMAT_TO_STRUCT[c]
msg_struct += f[0]
msg_mults.append(f[1])
except KeyError as e:
raise Exception("Unsupported format char: %s in message %s (%i)" % (c, msg_name, msg_type))
msg_struct = "<" + msg_struct # force little-endian
self.__msg_descrs[msg_type] = (msg_length, msg_name, msg_format, msg_labels, msg_struct, msg_mults)
self.__msg_labels[msg_name] = msg_labels
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))
self.__ptr += self.MSG_FORMAT_PACKET_LEN
def __parseMsg(self, msg_descr):
msg_length, msg_name, msg_format, msg_labels, msg_struct, msg_mults = msg_descr
if not self.__debug_out and self.__time_msg != None and msg_name == self.__time_msg and self.__csv_updated:
self.__printCSVRow()
self.__csv_updated = False
show_fields = self.__filterMsg(msg_name)
if (show_fields != None):
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] = _parseCString(data[i])
m = msg_mults[i]
if m != None:
data[i] = data[i] * m
if self.__debug_out:
s = []
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)))
else:
# update CSV data buffer
for i in range(len(data)):
label = msg_labels[i]
if label in show_fields:
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:
self.__printCSVRow()
self.__ptr += msg_length
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("\t-fPrint to file instead of stdout")
return
fn = sys.argv[1]
debug_out = False
correct_errors = False
msg_filter = []
csv_null = ""
csv_delim = ","
time_msg = "TIME"
file_name = None
opt = None
for arg in sys.argv[2:]:
if opt != None:
if opt == "d":
csv_delim = arg
elif opt == "n":
csv_null = arg
elif opt == "t":
time_msg = arg
elif opt == "f":
file_name = arg
elif opt == "m":
show_fields = "*"
a = arg.split("_")
if len(a) > 1:
show_fields = a[1].split(",")
msg_filter.append((a[0], show_fields))
opt = None
else:
if arg == "-v":
debug_out = True
elif arg == "-e":
correct_errors = True
elif arg == "-d":
opt = "d"
elif arg == "-n":
opt = "n"
elif arg == "-m":
opt = "m"
elif arg == "-t":
opt = "t"
elif arg == "-f":
opt = "f"
if csv_delim == "\\t":
csv_delim = "\t"
parser = SDLog2Parser()
parser.setCSVDelimiter(csv_delim)
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)
if __name__ == "__main__":
_main()
-1
View File
@@ -222,7 +222,6 @@ class Graph:
special_cases_sub = [
('sensors', r'voted_sensors_update\.cpp$', r'\binit_sensor_class\b\(([^,)]+)', r'^meta$'),
('mavlink', r'.*', r'\badd_orb_subscription\b\(([^,)]+)', r'^_topic$'),
('sdlog2', r'.*', None, r'^topic$'),
('logger', r'.*', None, r'^(topic|sub\.metadata|_polling_topic_meta)$'),
('uavcan', r'uavcan_main\.cpp$', r'\b_control_topics\[[0-9]\]=([^,)]+)', r'^_control_topics\[i\]$'),
@@ -91,7 +91,6 @@ set(config_module_list
# Logging
#
modules/logger
#modules/sdlog2
#
# Library modules
@@ -111,7 +111,6 @@ set(config_module_list
# Logging
#
modules/logger
modules/sdlog2
#
# Library modules
@@ -103,7 +103,6 @@ set(config_module_list
# Logging
#
modules/logger
modules/sdlog2
#
# Library modules
@@ -107,7 +107,6 @@ set(config_module_list
#
# Logging
#
modules/sdlog2
modules/logger
#
@@ -112,7 +112,6 @@ set(config_module_list
# Logging
#
modules/logger
modules/sdlog2
#
# Library modules
@@ -84,7 +84,6 @@ set(config_module_list
#
# Logging
#
modules/sdlog2
## modules/logger
#
@@ -134,7 +134,6 @@ set(config_module_list
# Logging
#
modules/logger
#modules/sdlog2
#
# Library modules
-1
View File
@@ -123,7 +123,6 @@ set(config_module_list
# Logging
#
#modules/logger
#modules/sdlog2
#
# Library modules
@@ -121,7 +121,6 @@ set(config_module_list
# Logging
#
modules/logger
modules/sdlog2
#
# Library modules
@@ -108,7 +108,6 @@ set(config_module_list
# Logging
#
modules/logger
modules/sdlog2
#
# Library modules
@@ -112,7 +112,6 @@ set(config_module_list
# Logging
#
modules/logger
modules/sdlog2
#
# Library modules
@@ -114,7 +114,6 @@ set(config_module_list
# Logging
#
modules/logger
modules/sdlog2
#
# Library modules
@@ -91,7 +91,6 @@ set(config_module_list
# Logging
#
modules/logger
modules/sdlog2
#
# Library modules
-1
View File
@@ -52,7 +52,6 @@ set(config_module_list
#
# Library modules
#
modules/sdlog2
modules/logger
modules/commander
modules/dataman
-1
View File
@@ -29,7 +29,6 @@ set(config_module_list
modules/sensors
modules/dataman
modules/sdlog2
modules/logger
modules/simulator
modules/commander
-1
View File
@@ -55,7 +55,6 @@ set(config_module_list
#
# Library modules
#
modules/sdlog2
modules/logger
modules/commander
modules/dataman
-1
View File
@@ -55,7 +55,6 @@ set(config_module_list
#
# Library modules
#
modules/sdlog2
modules/logger
modules/commander
modules/dataman
-1
View File
@@ -66,7 +66,6 @@ set(config_module_list
#
# Library modules
#
modules/sdlog2
modules/logger
modules/commander
modules/dataman
@@ -58,7 +58,6 @@ set(config_module_list
modules/muorb/krait
modules/sensors
modules/dataman
modules/sdlog2
modules/logger
modules/simulator
modules/commander
@@ -49,7 +49,6 @@ set(config_module_list
modules/muorb/krait
modules/sensors
modules/dataman
modules/sdlog2
modules/logger
modules/simulator
modules/commander
-1
View File
@@ -95,7 +95,6 @@ set(config_module_list
# Logging
#
modules/logger
modules/sdlog2
#
# Library modules
-1
View File
@@ -8,7 +8,6 @@ set(config_module_list
systemcmds/perf
modules/ekf2
modules/ekf2_replay
modules/sdlog2
modules/logger
)
+1 -1
View File
@@ -78,6 +78,6 @@ mavlink stream -r 50 -s SERVO_OUTPUT_RAW_0 -u 14556
mavlink stream -r 20 -s RC_CHANNELS -u 14556
mavlink stream -r 250 -s HIGHRES_IMU -u 14556
mavlink stream -r 10 -s OPTICAL_FLOW_RAD -u 14556
sdlog2 start -r 200 -e -t -a
logger start -e -t
mavlink boot_complete
replay trystart
+1 -1
View File
@@ -68,7 +68,7 @@ accelsim start
barosim start
gpssim start
measairspeedsim start
pwm_out_sim start start
pwm_out_sim start
sensors start
commander start
land_detector start vtol
+1 -1
View File
@@ -74,6 +74,6 @@ mavlink stream -r 50 -s SERVO_OUTPUT_RAW_0 -u 14556
mavlink stream -r 20 -s RC_CHANNELS -u 14556
mavlink stream -r 250 -s HIGHRES_IMU -u 14556
mavlink stream -r 10 -s OPTICAL_FLOW_RAD -u 14556
sdlog2 start -r 200 -e -t -a
logger start -e -t
mavlink boot_complete
replay trystart
-46
View File
@@ -1,46 +0,0 @@
############################################################################
#
# Copyright (c) 2015 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE modules__sdlog2
MAIN sdlog2
PRIORITY "SCHED_PRIORITY_MAX-30"
STACK_MAIN 1200
STACK_MAX 1600
COMPILE_FLAGS
-Wno-sign-compare # TODO: fix all sign-compare
SRCS
sdlog2.c
logbuffer.c
DEPENDS
)
-165
View File
@@ -1,165 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2013, 2014 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file logbuffer.c
*
* Ring FIFO buffer for binary log data.
*
* @author Anton Babushkin <anton.babushkin@me.com>
*/
#include <px4_defines.h>
#include <string.h>
#include <stdlib.h>
#include "logbuffer.h"
int logbuffer_init(struct logbuffer_s *lb, int size)
{
lb->size = size;
lb->write_ptr = 0;
lb->read_ptr = 0;
lb->data = NULL;
lb->perf_dropped = perf_alloc(PC_COUNT, "sd drop");
return PX4_OK;
}
int logbuffer_count(struct logbuffer_s *lb)
{
int n = lb->write_ptr - lb->read_ptr;
if (n < 0) {
n += lb->size;
}
return n;
}
int logbuffer_is_empty(struct logbuffer_s *lb)
{
return lb->read_ptr == lb->write_ptr;
}
bool logbuffer_write(struct logbuffer_s *lb, void *ptr, int size)
{
// allocate buffer if not yet present
if (lb->data == NULL) {
lb->data = malloc(lb->size);
}
// allocation failed, bail out
if (lb->data == NULL) {
return false;
}
// bytes available to write
int available = lb->read_ptr - lb->write_ptr - 1;
if (available < 0) {
available += lb->size;
}
if (size > available) {
// buffer overflow
perf_count(lb->perf_dropped);
return false;
}
char *c = (char *) ptr;
int n = lb->size - lb->write_ptr; // bytes to end of the buffer
if (n < size) {
// message goes over end of the buffer
memcpy(&(lb->data[lb->write_ptr]), c, n);
lb->write_ptr = 0;
} else {
n = 0;
}
// now: n = bytes already written
int p = size - n; // number of bytes to write
memcpy(&(lb->data[lb->write_ptr]), &(c[n]), p);
lb->write_ptr = (lb->write_ptr + p) % lb->size;
return true;
}
int logbuffer_get_ptr(struct logbuffer_s *lb, void **ptr, bool *is_part)
{
// bytes available to read
int available = lb->write_ptr - lb->read_ptr;
if (available == 0) {
return 0; // buffer is empty
}
int n = 0;
if (available > 0) {
// read pointer is before write pointer, all available bytes can be read
n = available;
*is_part = false;
} else {
// read pointer is after write pointer, read bytes from read_ptr to end of the buffer
n = lb->size - lb->read_ptr;
*is_part = lb->write_ptr > 0;
}
*ptr = &(lb->data[lb->read_ptr]);
return n;
}
void logbuffer_mark_read(struct logbuffer_s *lb, int n)
{
lb->read_ptr = (lb->read_ptr + n) % lb->size;
}
void logbuffer_free(struct logbuffer_s *lb)
{
if (lb->data) {
free(lb->data);
lb->write_ptr = 0;
lb->read_ptr = 0;
lb->data = NULL;
perf_free(lb->perf_dropped);
}
}
void logbuffer_reset(struct logbuffer_s *lb)
{
// Keep the buffer but reset the pointers.
lb->write_ptr = 0;
lb->read_ptr = 0;
}
-74
View File
@@ -1,74 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2013 PX4 Development Team. All rights reserved.
* Author: Anton Babushkin <anton.babushkin@me.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file logbuffer.h
*
* Ring FIFO buffer for binary log data.
*
* @author Anton Babushkin <anton.babushkin@me.com>
*/
#ifndef SDLOG2_RINGBUFFER_H_
#define SDLOG2_RINGBUFFER_H_
#include <stdbool.h>
#include <perf/perf_counter.h>
struct logbuffer_s {
// pointers and size are in bytes
int write_ptr;
int read_ptr;
int size;
char *data;
perf_counter_t perf_dropped;
};
int logbuffer_init(struct logbuffer_s *lb, int size);
int logbuffer_count(struct logbuffer_s *lb);
int logbuffer_is_empty(struct logbuffer_s *lb);
bool logbuffer_write(struct logbuffer_s *lb, void *ptr, int size);
int logbuffer_get_ptr(struct logbuffer_s *lb, void **ptr, bool *is_part);
void logbuffer_mark_read(struct logbuffer_s *lb, int n);
void logbuffer_free(struct logbuffer_s *lb);
void logbuffer_reset(struct logbuffer_s *lb);
#endif
-95
View File
@@ -1,95 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2012-2016 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Logging rate.
*
* A value of -1 indicates the commandline argument
* should be obeyed. A value of 0 sets the minimum rate,
* any other value is interpreted as rate in Hertz. This
* parameter is only read out before logging starts (which
* commonly is before arming).
*
* @unit Hz
* @min -1
* @max 250
* @group SD Logging
*/
PARAM_DEFINE_INT32(SDLOG_RATE, -1);
/**
* Extended logging mode
*
* A value of -1 indicates the command line argument
* should be obeyed. A value of 0 disables extended
* logging mode, a value of 1 enables it. This
* parameter is only read out before logging starts
* (which commonly is before arming).
*
* @min -1
* @max 1
* @value -1 Command Line
* @value 0 Disable
* @value 1 Enable
* @group SD Logging
*/
PARAM_DEFINE_INT32(SDLOG_EXT, -1);
/**
* Use timestamps only if GPS 3D fix is available
*
* Constrain the log folder creation
* to only use the time stamp if a 3D GPS lock is
* present.
*
* @boolean
* @group SD Logging
*/
PARAM_DEFINE_INT32(SDLOG_GPSTIME, 1);
/**
* Give logging app higher thread priority to avoid data loss.
* This is used for gathering replay logs for the ekf2 module.
*
* A value of 0 indicates that the default priority is used.
* Increasing the parameter in steps of one increases the priority.
*
* @min 0
* @max 3
* @value 0 Low priority
* @value 1 Default priority
* @value 2 Medium priority
* @value 3 Max priority
* @group SD Logging
*/
PARAM_DEFINE_INT32(SDLOG_PRIO_BOOST, 2);
File diff suppressed because it is too large Load Diff
-106
View File
@@ -1,106 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2013 PX4 Development Team. All rights reserved.
* Author: Anton Babushkin <anton.babushkin@me.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file sdlog2_format.h
*
* General log format structures and macro.
*
* @author Anton Babushkin <anton.babushkin@me.com>
*/
/*
Format characters in the format string for binary log messages
b : int8_t
B : uint8_t
h : int16_t
H : uint16_t
i : int32_t
I : uint32_t
f : float
n : char[4]
N : char[16]
Z : char[64]
c : int16_t * 100
C : uint16_t * 100
e : int32_t * 100
E : uint32_t * 100
L : int32_t latitude/longitude
M : uint8_t flight mode
q : int64_t
Q : uint64_t
*/
#ifndef SDLOG2_FORMAT_H_
#define SDLOG2_FORMAT_H_
#define LOG_PACKET_HEADER_LEN 3
#define LOG_PACKET_HEADER uint8_t head1, head2, msg_type
#define LOG_PACKET_HEADER_INIT(id) .head1 = HEAD_BYTE1, .head2 = HEAD_BYTE2, .msg_type = id
// once the logging code is all converted we will remove these from
// this header
#define HEAD_BYTE1 0xA3 // Decimal 163
#define HEAD_BYTE2 0x95 // Decimal 149
struct log_format_s {
uint8_t type;
uint8_t length; // full packet length including header
char name[4];
char format[16];
char labels[64];
};
#define LOG_FORMAT(_name, _format, _labels) { \
.type = LOG_##_name##_MSG, \
.length = sizeof(struct log_##_name##_s) + LOG_PACKET_HEADER_LEN, \
.name = #_name, \
.format = _format, \
.labels = _labels \
}
#define LOG_FORMAT_S(_name, _struct_name, _format, _labels) { \
.type = LOG_##_name##_MSG, \
.length = sizeof(struct log_##_struct_name##_s) + LOG_PACKET_HEADER_LEN, \
.name = #_name, \
.format = _format, \
.labels = _labels \
}
#define LOG_FORMAT_MSG 0x80
#define LOG_PACKET_SIZE(_name) LOG_PACKET_HEADER_LEN + sizeof(struct log_##_name##_s)
#endif /* SDLOG2_FORMAT_H_ */
File diff suppressed because it is too large Load Diff
-12
View File
@@ -152,18 +152,6 @@ PARAM_DEFINE_INT32(SYS_COMPANION, 157600);
*/
PARAM_DEFINE_INT32(SYS_PARAM_VER, 1);
/**
* SD logger
*
* @value 0 sdlog2 (legacy)
* @value 1 logger (default)
* @min 0
* @max 1
* @reboot_required true
* @group System
*/
PARAM_DEFINE_INT32(SYS_LOGGER, 1);
/**
* Enable stack checking
*