Skip to content

Commit

Permalink
ULog v1 support, various fixes and cleanup, jmalib-math module added
Browse files Browse the repository at this point in the history
  • Loading branch information
DrTon committed Jul 7, 2018
1 parent b2ad7ee commit d8cfd21
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 29 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
MicroAvia Java libraries.

#### Modules List
- jmalib-log: MicroAvia logs parsing (MicroAvia ULog v2)
- jmalib-log: MicroAvia logs parsing (MicroAvia ULog v1 and v2)

Based on deprecated [jMAVlib](https://github.com/DrTon/jMAVlib) project with some major improvements. Added Maven support.

Log parsing library in a typical scenario has ~100x speed up compared to original jMAVlib parser.
Log parser in a typical scenario has ~50x speed up compared to original jMAVlib parser.

#### Using with Maven
```
<dependency>
<groupId>com.microavia</groupId>
<artifactId>jmalib</artifactId>
<artifactId>jmalib-log</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.microavia.jmalib.log.ulog;

import com.microavia.jmalib.log.FormatErrorException;
import com.microavia.jmalib.log.ValueParser;

abstract class AbstractParser implements ValueParser {
Expand All @@ -10,7 +11,7 @@ abstract class AbstractParser implements ValueParser {
this.context = context;
}

private static AbstractParser createFromTypeString(LogParserContext context, String typeString) {
private static AbstractParser createFromTypeString(LogParserContext context, String typeString) throws FormatErrorException {
FieldParser field = FieldParser.create(context, typeString);
if (field != null) {
return field;
Expand All @@ -19,10 +20,10 @@ private static AbstractParser createFromTypeString(LogParserContext context, Str
if (struct != null) {
return struct.clone();
}
throw new RuntimeException("Unsupported type: " + typeString);
throw new FormatErrorException("Unsupported type: " + typeString);
}

static AbstractParser createFromFormatString(LogParserContext context, String formatStr) {
static AbstractParser createFromFormatString(LogParserContext context, String formatStr) throws FormatErrorException {
if (formatStr.contains("[")) {
// Array
String[] q = formatStr.split("\\[");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.microavia.jmalib.log.ulog;

import com.microavia.jmalib.log.FormatErrorException;

import java.nio.ByteBuffer;
import java.util.LinkedHashMap;
import java.util.Map;
Expand All @@ -13,7 +15,7 @@ private StructParser(LogParserContext context, LinkedHashMap<String, AbstractPar
setOffset(0);
}

StructParser(LogParserContext context, String formatStr) {
StructParser(LogParserContext context, String formatStr) throws FormatErrorException {
super(context);
if (formatStr.length() > 1) {
String[] fieldDescrs = formatStr.split(";");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/
public class ULogReader extends BinaryLogReader {
private static final byte SYNC_BYTE = (byte) '>';
private static final byte MESSAGE_TYPE_FORMAT = (byte) 'F';
private static final byte MESSAGE_TYPE_ADD = (byte) 'A';
private static final byte MESSAGE_TYPE_STRUCT = (byte) 'F';
private static final byte MESSAGE_TYPE_TOPIC = (byte) 'A';
private static final byte MESSAGE_TYPE_DATA = (byte) 'D';
private static final byte MESSAGE_TYPE_INFO = (byte) 'I';
private static final byte MESSAGE_TYPE_PARAMETER = (byte) 'P';
Expand All @@ -31,13 +31,14 @@ public class ULogReader extends BinaryLogReader {
private long sizeUpdates = -1;
private long sizeMicroseconds = -1;
private long startMicroseconds = -1;
private long timeLast = -1;
private long timeLast = Long.MIN_VALUE;
private long utcTimeReference = -1;
private Map<String, Object> version = new HashMap<>();
private Map<String, Object> parameters = new HashMap<>();
private List<Exception> errors = new ArrayList<>();
private int logVersion = 0;
private int headerSize = 4;
private int msgDataTimestampOffset = 3;
private LogParserContext context = new LogParserContext();

public ULogReader(String fileName) throws IOException, FormatErrorException {
Expand All @@ -46,8 +47,9 @@ public ULogReader(String fileName) throws IOException, FormatErrorException {
}

public static void main(String[] args) throws Exception {
ULogReader reader = new ULogReader("test.ulg");
ULogReader reader = new ULogReader("test_long_v1.ulg");
reader.addSubscription("ATTITUDE_POSITION.alt_baro");
reader.seek(0);
long tStart = System.currentTimeMillis();
try {
while (true) {
Expand Down Expand Up @@ -120,13 +122,18 @@ private void updateStatistics() throws IOException, FormatErrorException {
if (logVersionStr.startsWith("ULG")) {
logVersion = Integer.parseInt(logVersionStr.substring(3));
headerSize = 4;
if (logVersion >= 2) {
msgDataTimestampOffset = 3;
} else {
msgDataTimestampOffset = 2;
}
} else {
throw new FormatErrorException("Unsupported file format");
}
startMicroseconds = -1;
timeLast = -1;
sizeUpdates = 0;
fieldsList = new HashMap<>();
timeLast = Long.MIN_VALUE;
try {
while (true) {
readMessage(this::handleHeaderMessage);
Expand Down Expand Up @@ -189,9 +196,10 @@ public void removeAllSubscriptions() {
@Override
public long readUpdate() throws IOException {
updatedSubscriptions.clear();
timeLast = Long.MIN_VALUE;
do {
readMessage(this::handleDataMessage);
} while (timeLast < 0);
} while (timeLast == Long.MIN_VALUE);
return timeLast;
}

Expand All @@ -203,6 +211,7 @@ public Set<Subscription> getUpdatedSubscriptions() {
@Override
public boolean seek(long seekTime) throws IOException {
position(dataStart);
timeLast = Long.MIN_VALUE;
if (seekTime == 0) { // Seek to start of log
return true;
}
Expand All @@ -211,9 +220,11 @@ public boolean seek(long seekTime) throws IOException {
while (timeLast < seekTime) {
readMessage((pos, msgType, msgSize) -> {
if (msgType == MESSAGE_TYPE_DATA) {
timeLast = buffer.getLong(buffer.position() + 3);
timeLast = buffer.getLong(buffer.position() + msgDataTimestampOffset);
if (timeLast >= seekTime) {
return; // Dont consume message with timestamp > seekTime
// Time found, reset buffer to start of the message
position(pos);
return;
}
}
buffer.position(buffer.position() + msgSize);
Expand Down Expand Up @@ -268,7 +279,7 @@ private void handleHeaderMessage(long pos, int msgType, int msgSize) throws IOEx
if (dataStart == 0) {
dataStart = pos;
}
long timestamp = buffer.getLong(buffer.position() + 2);
long timestamp = buffer.getLong(buffer.position() + msgDataTimestampOffset);
if (startMicroseconds < 0) {
startMicroseconds = timestamp;
}
Expand All @@ -277,22 +288,44 @@ private void handleHeaderMessage(long pos, int msgType, int msgSize) throws IOEx
buffer.position(buffer.position() + msgSize);
break;
}
case MESSAGE_TYPE_FORMAT: {
String[] descr = getString(buffer, msgSize).split(":");
String name = descr[0];
if (descr.length > 1) {
StructParser struct = new StructParser(context, descr[1]);
System.out.printf("STRUCT %s: %s\n", name, struct);
context.getStructs().put(name, struct);
case MESSAGE_TYPE_STRUCT: {
if (logVersion <= 1) {
int msgId = buffer.get() & 0xFF;
int formatLen = buffer.getShort() & 0xFFFF;
String[] descr = getString(buffer, formatLen).split(":");
String name = descr[0];
if (descr.length > 1) {
StructParser struct = null;
try {
struct = new StructParser(context, descr[1]);
} catch (FormatErrorException e) {
errors.add(new FormatErrorException(pos, "Error parsing type definition", e));
break;
}
context.getStructs().put(name, struct);
topicByName.put(name, new Topic(name, struct, msgId));
}
} else {
String[] descr = getString(buffer, msgSize).split(":");
String name = descr[0];
if (descr.length > 1) {
StructParser struct = null;
try {
struct = new StructParser(context, descr[1]);
} catch (Exception e) {
errors.add(new FormatErrorException(pos, "Error parsing struct", e));
break;
}
context.getStructs().put(name, struct);
}
}
break;
}
case MESSAGE_TYPE_ADD: {
case MESSAGE_TYPE_TOPIC: {
int msgId = buffer.getShort() & 0xFFFF;
String[] descr = getString(buffer, msgSize - 2).split(":");
String name = descr[0];
String structName = descr[1];
System.out.printf("ADD: %s:%s\n", name, structName);
StructParser struct = context.getStructs().get(structName);
Topic topic = new Topic(name, struct, msgId);
topicByName.put(name, topic);
Expand All @@ -303,7 +336,13 @@ private void handleHeaderMessage(long pos, int msgType, int msgSize) throws IOEx
int keyLen = buffer.get() & 0xFF;
String[] keyDescr = getString(buffer, keyLen).split(" ");
String key = keyDescr[1];
AbstractParser field = AbstractParser.createFromFormatString(context, keyDescr[0]);
AbstractParser field = null;
try {
field = AbstractParser.createFromFormatString(context, keyDescr[0]);
} catch (FormatErrorException e) {
errors.add(new FormatErrorException(pos, "Error parsing info", e));
break;
}
Object value = field.parse(buffer);
buffer.position(buffer.position() + field.size());
switch (key) {
Expand All @@ -329,7 +368,13 @@ private void handleHeaderMessage(long pos, int msgType, int msgSize) throws IOEx
int keyLen = buffer.get() & 0xFF;
String[] keyDescr = getString(buffer, keyLen).split(" ");
String key = keyDescr[1];
AbstractParser field = AbstractParser.createFromFormatString(context, keyDescr[0]);
AbstractParser field = null;
try {
field = AbstractParser.createFromFormatString(context, keyDescr[0]);
} catch (FormatErrorException e) {
errors.add(new FormatErrorException(pos, "Error parsing parameter", e));
break;
}
Object value = field.parse(buffer);
buffer.position(buffer.position() + field.size());
parameters.put(key, value);
Expand Down Expand Up @@ -367,9 +412,8 @@ private void addFieldsToList(String path, AbstractParser value) {

private void handleDataMessage(long pos, int msgType, int msgSize) {
int bp = buffer.position();
timeLast = -1;
if (msgType == MESSAGE_TYPE_DATA) {
int msgId = buffer.getShort() & 0xFFFF;
int msgId = logVersion >= 2 ? (buffer.getShort() & 0xFFFF) : (buffer.get() & 0xFF);
List<Subscription> subs = subscriptions.get(msgId);
if (subs != null) {
int multiId = buffer.get() & 0xFF;
Expand Down
13 changes: 13 additions & 0 deletions jmalib-math/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jmalib</artifactId>
<groupId>com.microavia</groupId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>jmalib-math</artifactId>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.microavia.jmalib.math;

import static java.lang.Math.*;

/**
* User: ton Date: 11.07.13 Time: 22:11
*/
public class GlobalPositionProjector {
private static double r_earth = 6371000.0;
private boolean inited;
private double lat0;
private double lon0;
private double alt0;
private double cos_lat0;
private double sin_lat0;

public void reset() {
inited = false;
}

public boolean isInited() {
return inited;
}

public void init(LatLonAlt ref) {
inited = true;
lat0 = ref.lat * PI / 180.0;
lon0 = ref.lon * PI / 180.0;
alt0 = ref.alt;
cos_lat0 = cos(lat0);
sin_lat0 = sin(lat0);
}

public double[] project(LatLonAlt p) {
if (!inited) {
throw new RuntimeException("Not initialized");
}
double lat_rad = p.lat * PI / 180.0;
double lon_rad = p.lon * PI / 180.0;
double sin_lat = sin(lat_rad);
double cos_lat = cos(lat_rad);
double cos_d_lon = cos(lon_rad - lon0);
double c = acos(sin_lat0 * sin_lat + cos_lat0 * cos_lat * cos_d_lon);
double k = (c == 0.0) ? 1.0 : (c / sin(c));
double y = k * cos_lat * sin(lon_rad - lon0) * r_earth;
double x = k * (cos_lat0 * sin_lat - sin_lat0 * cos_lat * cos_d_lon) * r_earth;
double z = alt0 - p.alt;
return new double[]{x, y, z};
}

public LatLonAlt reproject(double[] v) {
if (!inited) {
throw new RuntimeException("Not initialized");
}
double x_rad = v[0] / r_earth;
double y_rad = v[1] / r_earth;
double c = sqrt(x_rad * x_rad + y_rad * y_rad);
double sin_c = sin(c);
double cos_c = cos(c);
double lat_rad;
double lon_rad;
if (c != 0.0) {
lat_rad = asin(cos_c * sin_lat0 + (x_rad * sin_c * cos_lat0) / c);
lon_rad = (lon0 + atan2(y_rad * sin_c, c * cos_lat0 * cos_c - x_rad * sin_lat0 * sin_c));
} else {
lat_rad = lat0;
lon_rad = lon0;
}
return new LatLonAlt(lat_rad * 180.0 / Math.PI, lon_rad * 180.0 / Math.PI, alt0 - v[2]);
}
}
Loading

0 comments on commit d8cfd21

Please sign in to comment.