Skip to content

Commit

Permalink
Added signalLevel and isMlat.
Browse files Browse the repository at this point in the history
Added two test cases to check for proper detection of the magic MLAT
timestamp.
  • Loading branch information
wiseman committed May 24, 2016
1 parent d0f77e0 commit 107a6f2
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 30 deletions.
75 changes: 53 additions & 22 deletions src/main/java/com/lemondronor/modesbeast/BeastMessageParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,40 @@
* This is a Java implementation of the parser from Virtual Radar Server.
*/
public class BeastMessageParser {
static final int ESCAPE = 0x1A;

static final int BEAST_ESCAPE = 0x1A;
static final byte[] mlatGeneratedMessageTimestamp = new byte[] { (byte) 0xFF, 0x00, 0x4D, 0x4C, 0x41, 0x54 };

private class ExtractResult {
int endOfPacket;
int startOfPacket;
int dataLength;
int signalLevel;

ExtractResult(int endOfPacket, int startOfPacket, int dataLength,
int signalLevel) {
this.endOfPacket = endOfPacket;
this.startOfPacket = startOfPacket;
this.dataLength = dataLength;
this.signalLevel = signalLevel;
}
}

private byte[] readBuffer;
private int readBufferLength;
private byte[] payload;
private byte[] timestampBytes;
private boolean sawFirstPacket;
private boolean isBinaryFormat;
private boolean hasParity;
private boolean hasMlatPrefix;
private boolean isMlat;
private byte avrMessageStartIndicator;
private boolean streamFormatIsEstablished;
private ByteBuffer extractedBytes;

public BeastMessageParser() {
this.timestampBytes = new byte[6];
}

/**
Expand Down Expand Up @@ -51,16 +71,18 @@ public Collection<ExtractedBytes> parse(byte[] bytes, int offset, int bytesRead)
while (startOfPacket != -1 && startOfPacket < readBufferLength) {
int endOfPacket;
int dataLength = 0;
int signalLevel = -1;
if (!isBinaryFormat) {
endOfPacket = ArrayUtils.indexOf(readBuffer, (byte) ';', startOfPacket);
if (endOfPacket >= (readBufferLength - startOfPacket)) {
endOfPacket = ArrayUtils.INDEX_NOT_FOUND;
}
} else {
int[] extractResult = extractBinaryPayload(startOfPacket, dataLength);
endOfPacket = extractResult[0];
startOfPacket = extractResult[1];
dataLength = extractResult[2];
ExtractResult extractResult = extractBinaryPayload(startOfPacket, dataLength);
endOfPacket = extractResult.endOfPacket;
startOfPacket = extractResult.startOfPacket;
dataLength = extractResult.dataLength;
signalLevel = extractResult.signalLevel;
}
if (endOfPacket == -1) {
break;
Expand All @@ -73,9 +95,11 @@ public Collection<ExtractedBytes> parse(byte[] bytes, int offset, int bytesRead)
}

if (dataLength == 7 || dataLength == 14) {
ExtractedBytes extractedBytes = new ExtractedBytes(
Arrays.copyOf(payload, dataLength),
hasParity || isBinaryFormat);
ExtractedBytes extractedBytes = new ExtractedBytes()
.bytes(Arrays.copyOf(payload, dataLength))
.hasParity(hasParity || isBinaryFormat)
.signalLevel(signalLevel)
.isMlat(isMlat);
result.add(extractedBytes);
}
startOfPacket = findStartIndex(firstByteAfterLastValidPacket);
Expand Down Expand Up @@ -154,22 +178,22 @@ private int extractHexDigitValue(byte by) {
private boolean establishStreamFormat() {
if (!streamFormatIsEstablished) {
isBinaryFormat = ArrayUtils.indexOf(
readBuffer, (byte) ESCAPE, 0, readBufferLength) != ArrayUtils.INDEX_NOT_FOUND;
readBuffer, (byte) BEAST_ESCAPE, 0, readBufferLength) != ArrayUtils.INDEX_NOT_FOUND;
if (isBinaryFormat) {
streamFormatIsEstablished = true;
} else if (readBufferLength > 22) {
for (byte ch : readBuffer) {
switch (ch) {
case 0x2a:
case 0x2a: // '*'
streamFormatIsEstablished = true;
hasParity = true;
avrMessageStartIndicator = ch;
break;
case 0x3a:
case 0x3a: // ':'
streamFormatIsEstablished = true;
avrMessageStartIndicator = ch;
break;
case 0x40:
case 0x40: // '@'
streamFormatIsEstablished = true;
hasParity = true;
hasMlatPrefix = true;
Expand Down Expand Up @@ -201,9 +225,9 @@ private int findStartIndex(int start) {
} else {
for (int i = start; i < readBufferLength; ++i) {
byte ch = readBuffer[i];
if (ch == ESCAPE) {
if (ch == BEAST_ESCAPE) {
if (++i < readBufferLength) {
if (readBuffer[i] != ESCAPE) {
if (readBuffer[i] != BEAST_ESCAPE) {
result = i;
break;
}
Expand All @@ -214,7 +238,7 @@ private int findStartIndex(int start) {
return result;
}

private int[] extractBinaryPayload(int startOfPacket, int dataLength) {
private ExtractResult extractBinaryPayload(int startOfPacket, int dataLength) {
dataLength = 0;
switch (readBuffer[startOfPacket++]) {
case 0x31:
Expand All @@ -233,15 +257,26 @@ private int[] extractBinaryPayload(int startOfPacket, int dataLength) {
}
int si = startOfPacket;
int di = 0;
int signalLevel = -1;
isMlat = true;
for (; si < readBufferLength && di < 7; ++si, ++di) {
byte ch = readBuffer[si];
if (ch == ESCAPE && ++si > readBufferLength) {
if (ch == BEAST_ESCAPE && ++si > readBufferLength) {
break;
}
if (di == 6) {
// Make sure, e.g., 0xFF gets converted into 255.
signalLevel = ch & 0xFF;
} else {
timestampBytes[di] = ch;
if (isMlat && ch != mlatGeneratedMessageTimestamp[di]) {
isMlat = false;
}
}
}
for (di = 0; si < readBufferLength && di < dataLength; ++si) {
byte ch = readBuffer[si];
if (ch == ESCAPE) {
if (ch == BEAST_ESCAPE) {
if (++si >= readBufferLength) {
break;
}
Expand All @@ -250,11 +285,7 @@ private int[] extractBinaryPayload(int startOfPacket, int dataLength) {
payload[di++] = ch;
}
int endOfPacket = di != dataLength ? ArrayUtils.INDEX_NOT_FOUND : si;
int[] result = new int[3];
result[0] = endOfPacket;
result[1] = startOfPacket;
result[2] = dataLength;
return result;
return new ExtractResult(endOfPacket, startOfPacket, dataLength, signalLevel);
}

/**
Expand Down
29 changes: 28 additions & 1 deletion src/main/java/com/lemondronor/modesbeast/ExtractedBytes.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,37 @@
public class ExtractedBytes {
public byte[] bytes;
public boolean hasParity;
public boolean badChecksum;
public int signalLevel;
public boolean isMlat;

public ExtractedBytes(byte[] bytes, boolean hasParity) {
public ExtractedBytes() {
signalLevel = -1;
}

public ExtractedBytes bytes(byte[] bytes) {
this.bytes = bytes;
return this;
}

public ExtractedBytes badChecksum(boolean badChecksum) {
this.badChecksum = badChecksum;
return this;
}

public ExtractedBytes hasParity(boolean hasParity) {
this.hasParity = hasParity;
return this;
}

public ExtractedBytes signalLevel(int signalLevel) {
this.signalLevel = signalLevel;
return this;
}

public ExtractedBytes isMlat(boolean isMlat) {
this.isMlat = isMlat;
return this;
}

public byte[] getByteArray() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,18 @@ public void checkTestSpec() {
e1 = extracteds.get(0);
}
if (spec.extracted1 != null) {
assertNotNull(e1);
assertNotNull(spec.comment, e1);
assertArrayEquals(
desc(spec.comment, spec.extracted1, e1.getByteArray()),
spec.extracted1, e1.getByteArray());
assertEquals(spec.hasParity1, e1.hasParity);
assertEquals(spec.comment, spec.hasParity1, e1.hasParity);
assertEquals(spec.comment, spec.badChecksum1, e1.badChecksum);
if (spec.signalLevel1 != null) {
assertEquals(spec.comment, spec.signalLevel1.intValue(), e1.signalLevel);
} else {
assertEquals(spec.comment, -1, e1.signalLevel);
}
assertEquals(spec.comment, spec.isMlat1, e1.isMlat);
}
ExtractedBytes e2 = null;
if (extracteds.size() > 1) {
Expand All @@ -66,6 +73,13 @@ public void checkTestSpec() {
desc(spec.comment, spec.extracted2, e2.getByteArray()),
spec.extracted2, e2.getByteArray());
assertEquals(spec.hasParity2, e2.hasParity);
assertEquals(spec.badChecksum2, e2.badChecksum);
if (spec.signalLevel2 != null) {
assertEquals(spec.signalLevel2.intValue(), e2.signalLevel);
} else {
assertEquals(-1, e2.signalLevel);
}
assertEquals(spec.isMlat2, e2.isMlat);
} else {
assertNull(e2);
}
Expand Down
8 changes: 8 additions & 0 deletions src/test/java/com/lemondronor/modesbeast/TestSpec.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ public class TestSpec {
public byte[] extracted1;
public Boolean hasParity1;
public Boolean badChecksum1;
public Integer signalLevel1;
public Boolean isMlat1;
public byte[] extracted2;
public Boolean hasParity2;
public Boolean badChecksum2;
public Integer signalLevel2;
public Boolean isMlat2;
public String comment;

/**
Expand All @@ -33,9 +37,13 @@ public static Collection<TestSpec> readFromFile(String path) {
spec.extracted1 = parsePacket((String)desc.get("Extracted1"));
spec.hasParity1 = (Boolean)desc.get("HasParity1");
spec.badChecksum1 = (Boolean)desc.get("BadChecksum1");
spec.signalLevel1 = (Integer)desc.get("SignalLevel1");
spec.isMlat1 = (Boolean)desc.get("IsMlat1");
spec.extracted2 = parsePacket((String)desc.get("Extracted2"));
spec.hasParity2 = (Boolean)desc.get("HasParity2");
spec.badChecksum2 = (Boolean)desc.get("BadChecksum2");
spec.signalLevel2 = (Integer)desc.get("SignalLevel2");
spec.isMlat2 = (Boolean)desc.get("IsMlat2");
spec.comment = (String) desc.get("Comment");
specs.add(spec);
}
Expand Down
Loading

0 comments on commit 107a6f2

Please sign in to comment.