Skip to content

Commit

Permalink
Merge pull request #51 from terminal2/SurfacePosition
Browse files Browse the repository at this point in the history
SurfacePosition
  • Loading branch information
Douglasdc3 committed Apr 1, 2023
2 parents 412d187 + 684e1f9 commit 07ff26d
Show file tree
Hide file tree
Showing 13 changed files with 642 additions and 196 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ Most features of the DF17/18 protocol have been implemented, some message lack s
| 2 | Aircraft Identification || |
| 3 | Aircraft Identification || |
| 4 | Aircraft Identification || |
| 5 | Surface Position | | Not implemented yet |
| 6 | Surface Position | | Not implemented yet |
| 7 | Surface Position | | Not implemented yet |
| 8 | Surface Position | | Not implemented yet |
| 5 | Surface Position | | |
| 6 | Surface Position | | |
| 7 | Surface Position | | |
| 8 | Surface Position | | |
| 9 | Airborne Position || |
| 10 | Airborne Position || |
| 11 | Airborne Position || |
Expand Down
2 changes: 1 addition & 1 deletion examples/gui/src/main/java/example/Demo.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
public class Demo extends JPanel {
private static final Logger logger = LoggerFactory.getLogger(Demo.class);

private static final String IP = "192.168.178.190";
private static final String IP = "127.0.0.1";
private static final int PORT = 30002;
private static final double LAT = 51;
private static final double LON = 2;
Expand Down
49 changes: 48 additions & 1 deletion src/main/java/aero/t2s/modes/CprPosition.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,33 @@
public class CprPosition {
private double lat;
private double lon;
private boolean valid;
private boolean surface = false;
private boolean valid = false;
private double latZone;
private double lonZone;
private long time;

public CprPosition() {
this.lat = 0.0;
this.lon = 0.0;
this.surface = false;
this.valid = false;
}

public CprPosition(double lat, double lon, boolean surface) {
setLatLon(lat ,lon);
this.surface = surface;
}

public CprPosition(double lat, double lon) {
setLatLon(lat ,lon);
}

public CprPosition(int cprLat, int cprLon, boolean surface) {
setLatLon(cprLat / (double) (1 << 17), cprLon / (double) (1 << 17));
this.surface = surface;
}

public void setLatLon(double lat, double lon) {
this.lat = lat;
this.lon = lon;
Expand All @@ -40,6 +55,34 @@ public double getLon() {
return lon;
}

public void setSurface(boolean surface) {
this.surface = surface;
}

public boolean getSurface() {
return this.surface;
}

public void setZones(double latZone, double lonZone) {
this.latZone = latZone;
this.lonZone = lonZone;
}
public void setLatZone(double zone) {
this.latZone = zone;
}

public double getLatZone() {
return this.latZone;
}

public void setLonZone(double zone) {
this.lonZone = zone;
}

public double getLonZone() {
return this.lonZone;
}

public void setTime(long time) {
this.time = time;
}
Expand All @@ -52,6 +95,10 @@ public boolean isValid() {
return valid;
}

public void setValid(boolean valid) {
this.valid = valid;
}

public boolean isExpired() {
return time < Instant.now().minusSeconds(10).toEpochMilli();
}
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/aero/t2s/modes/ModeSHandler.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package aero.t2s.modes;

import aero.t2s.modes.decoder.df.DownlinkFormat;
import aero.t2s.modes.decoder.df.df17.AirbornePosition;
import aero.t2s.modes.decoder.df.df17.PositionUpdate;

import java.util.function.Consumer;

abstract public class ModeSHandler {
protected double originLat;
protected double originLon;
protected Consumer<Track> onDeleted = track -> {};
protected Consumer<Track> onCreated = track -> {};
protected Consumer<Track> onUpdated = track -> {};
Expand Down Expand Up @@ -43,10 +45,10 @@ protected short[] toData(final String input) throws EmptyMessageException, ModeA
}

public void start() {
AirbornePosition.start();
PositionUpdate.start(originLat, originLon);
}

public void stop() {
AirbornePosition.stop();
PositionUpdate.stop();
}
}
2 changes: 2 additions & 0 deletions src/main/java/aero/t2s/modes/ModeSMessageHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public class ModeSMessageHandler extends ModeSHandler {
private Consumer<DownlinkFormat> onMessage;

public ModeSMessageHandler(double originLat, double originLon) {
this.originLat = originLat;
this.originLon = originLon;
this.decoder = new Decoder(new HashMap<>(), originLat, originLon, ModeSDatabase.createDatabase());
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/aero/t2s/modes/ModeSTrackHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class ModeSTrackHandler extends ModeSHandler {

public ModeSTrackHandler(Map<String, Track> tracks, double originLat, double originLon, ModeSDatabase database) {
this.tracks = tracks;
this.originLat = originLat;
this.originLon = originLon;
this.decoder = new Decoder(tracks, originLat, originLon, database);

timer = new Timer();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/aero/t2s/modes/decoder/df/DF17.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public DF17 decode() {
case 6:
case 7:
case 8:
extendedSquitter = new SurfacePosition(data);
extendedSquitter = new SurfacePosition(data, getIcao());
break;
case 19:
extendedSquitter = new AirborneVelocity(data);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/aero/t2s/modes/decoder/df/DF18.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public DF18 decode() {
case 6:
case 7:
case 8:
extendedSquitter = new SurfacePosition(data);
extendedSquitter = new SurfacePosition(data, getIcao());
break;
case 19:
extendedSquitter = new AirborneVelocity(data);
Expand Down
189 changes: 8 additions & 181 deletions src/main/java/aero/t2s/modes/decoder/df/df17/AirbornePosition.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import aero.t2s.modes.Track;
import aero.t2s.modes.CprPosition;
import aero.t2s.modes.constants.*;
import aero.t2s.modes.decoder.Common;
import aero.t2s.modes.registers.Register05;
import aero.t2s.modes.registers.Register05V0;
import aero.t2s.modes.registers.Register05V2;
Expand All @@ -18,12 +17,9 @@ public class AirbornePosition extends ExtendedSquitter {
private boolean altitudeSourceBaro;
private int altitude;

private boolean positionAvailable;

private double lat;
private double lon;
private static Map<String, PositionUpdate> cache = new HashMap<>();
private static Timer cacheCleanup;
private boolean positionAvailable;

public AirbornePosition(short[] data, String address) {
super(data);
Expand Down Expand Up @@ -58,39 +54,14 @@ public AirbornePosition decode() {
cprLon = cprLon | (data[9] << 8);
cprLon = cprLon | data[10];


if (!cache.containsKey(address)) {
if (!isCprEven) {
return this;
}

synchronized (cache) {
cache.putIfAbsent(address, new PositionUpdate(
new CprPosition(cprLat / (double)(1 << 17), cprLon / (double)(1 << 17))
));
}
}

PositionUpdate positionUpdate;
synchronized (cache) {
positionUpdate = cache.get(address);
}
if (isCprEven) {
positionUpdate.setEven(new CprPosition(cprLat / (double) (1 << 17), cprLon / (double) (1 << 17)));
} else {
positionUpdate.setOdd(new CprPosition(cprLat / (double) (1 << 17), cprLon / (double) (1 << 17)));
}

if (positionUpdate.isComplete()) {
calculateGlobal(positionUpdate.even, positionUpdate.odd);
} else if (positionUpdate.isPreviousPositionAvailable() && positionUpdate.isPreviousPositionAvailable()) {
calculateLocal(positionUpdate.odd, true, positionUpdate.previousLat, positionUpdate.previousLon);
}

if (positionAvailable) {
positionUpdate.setPreviousPosition(this.lat, this.lon);
CprPosition newPosition = PositionUpdate.calculate(address, isCprEven, new CprPosition(cprLat, cprLon, false));
if (newPosition != null) {
this.lat = newPosition.getLat();
this.lon = newPosition.getLon();
this.positionAvailable = true;
} else {
this.positionAvailable = false;
}

return this;
}

Expand Down Expand Up @@ -230,88 +201,6 @@ private AltitudeSource determineAltitudeSource() {
return AltitudeSource.GNSS_HAE;
}

private void calculateLocal(CprPosition cpr, boolean isOdd, double previousLat, double previousLon) {

double dlat = isOdd ? 360.0 / 59.0 : 360.0 / 60.0;

double j = Math.floor(previousLat / dlat) + Math.floor((previousLat % dlat) / dlat - cpr.getLat() + 0.5);

double newLat = dlat * (j + previousLat);

double nl = NL(newLat) - (isOdd ? 1.0 : 0.0);
double dlon = nl > 0 ? 360.0 / nl : 360;

double m = Math.floor(previousLon / dlon) + Math.floor((previousLon % dlon) / dlon - cpr.getLon() + 0.5);
double newLon = dlon * (m + lon);

//TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range
//TODO Should be a sanity-check here to see if the calculated movement since the last update is too far
this.lat = newLat;
this.lon = newLon;
this.positionAvailable = true;
}

private void calculateGlobal(CprPosition cprEven, CprPosition cprOdd) {
double dLat0 = 360.0 / 60.0;
double dLat1 = 360.0 / 59.0;

double j = Math.floor(59.0 * cprEven.getLat() - 60.0 * cprOdd.getLat() + 0.5);

double latEven = dLat0 * (j % 60.0 + cprEven.getLat());
double latOdd = dLat1 * (j % 59.0 + cprOdd.getLat());

if (latEven >= 270.0 && latEven <= 360.0) {
latEven -= 360.0;
}

if (latOdd >= 270.0 && latOdd <= 360.0) {
latOdd -= 360.0;
}

if (NL(latEven) != NL(latOdd)) {
return;
}

double lat;
double lon;
if (cprEven.getTime() > cprOdd.getTime()) {
double ni = cprN(latEven, 0);
double m = Math.floor(cprEven.getLon() * (NL(latEven) - 1) - cprOdd.getLon() * NL(latEven) + 0.5);

lat = latEven;
lon = (360d / ni) * (m % ni + cprEven.getLon());
} else {
double ni = cprN(latOdd, 1);
double m = Math.floor(cprEven.getLon() * (NL(latOdd) - 1) - cprOdd.getLon() * NL(latOdd) + 0.5);

lat = latOdd;
lon = (360d / ni) * (m % ni + cprOdd.getLon());
}

if (lon > 180d) {
lon -= 360d;
}

//TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range,
this.lat = lat;
this.lon = lon;
this.positionAvailable = true;
}
private double cprN(double lat, double isOdd) {
double nl = NL(lat) - isOdd;

return nl > 1 ? nl : 1;
}

private double NL(double lat) {
if (lat == 0) return 59;
else if (Math.abs(lat) == 87) return 2;
else if (Math.abs(lat) > 87) return 1;

double tmp = 1 - (1 - Math.cos(Math.PI / (2.0 * 15.0))) / Math.pow(Math.cos(Math.PI / 180.0 * Math.abs(lat)), 2);
return Math.floor(2 * Math.PI / Math.acos(tmp));
}

private int calculateAltitude(short[] data, int typeCode) {
// TODO this should use AltitudeEncoding class flagged with mBit false feature.
int n = (data[5] >>> 1) << 4;
Expand All @@ -321,66 +210,4 @@ private int calculateAltitude(short[] data, int typeCode) {

return (n * qBit) - 1000;
}

public static void start() {
AirbornePosition.cache.clear();
AirbornePosition.cacheCleanup.schedule(new TimerTask() {
@Override
public void run() {
List<String> expired = new LinkedList<>();

synchronized (cache) {
cache.entrySet().stream().filter(entry -> entry.getValue().isExpired()).forEach(entry -> expired.add(entry.getKey()));
expired.forEach(cache::remove);
}
}
}, 0, 10_000);
}

public static void stop() {
AirbornePosition.cacheCleanup.cancel();
AirbornePosition.cacheCleanup = null;

AirbornePosition.cache.clear();
}

class PositionUpdate {
private CprPosition even;
private CprPosition odd;


private boolean previousPositionAvailable = false;
private double previousLat;
private double previousLon;

public PositionUpdate(CprPosition even) {
this.even = even;
}

public void setEven(CprPosition even) {
this.even = even;
this.odd = null;
}

public void setOdd(CprPosition odd) {
this.odd = odd;
}

public void setPreviousPosition(double lat, double lon) {
this.previousLat = lat;
this.previousLon = lon;
}

public boolean isPreviousPositionAvailable() {
return this.previousPositionAvailable;
}

public boolean isComplete() {
return even != null && odd != null;
}

public boolean isExpired() {
return even.isExpired() || odd.isExpired();
}
}
}
Loading

0 comments on commit 07ff26d

Please sign in to comment.