Skip to content

Commit 07ff26d

Browse files
authored
Merge pull request #51 from terminal2/SurfacePosition
SurfacePosition
2 parents 412d187 + 684e1f9 commit 07ff26d

File tree

13 files changed

+642
-196
lines changed

13 files changed

+642
-196
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ Most features of the DF17/18 protocol have been implemented, some message lack s
3434
| 2 | Aircraft Identification || |
3535
| 3 | Aircraft Identification || |
3636
| 4 | Aircraft Identification || |
37-
| 5 | Surface Position | | Not implemented yet |
38-
| 6 | Surface Position | | Not implemented yet |
39-
| 7 | Surface Position | | Not implemented yet |
40-
| 8 | Surface Position | | Not implemented yet |
37+
| 5 | Surface Position | | |
38+
| 6 | Surface Position | | |
39+
| 7 | Surface Position | | |
40+
| 8 | Surface Position | | |
4141
| 9 | Airborne Position || |
4242
| 10 | Airborne Position || |
4343
| 11 | Airborne Position || |

examples/gui/src/main/java/example/Demo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
public class Demo extends JPanel {
2424
private static final Logger logger = LoggerFactory.getLogger(Demo.class);
2525

26-
private static final String IP = "192.168.178.190";
26+
private static final String IP = "127.0.0.1";
2727
private static final int PORT = 30002;
2828
private static final double LAT = 51;
2929
private static final double LON = 2;

src/main/java/aero/t2s/modes/CprPosition.java

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,33 @@
55
public class CprPosition {
66
private double lat;
77
private double lon;
8-
private boolean valid;
8+
private boolean surface = false;
9+
private boolean valid = false;
10+
private double latZone;
11+
private double lonZone;
912
private long time;
1013

1114
public CprPosition() {
1215
this.lat = 0.0;
1316
this.lon = 0.0;
17+
this.surface = false;
1418
this.valid = false;
1519
}
20+
21+
public CprPosition(double lat, double lon, boolean surface) {
22+
setLatLon(lat ,lon);
23+
this.surface = surface;
24+
}
25+
1626
public CprPosition(double lat, double lon) {
1727
setLatLon(lat ,lon);
1828
}
1929

30+
public CprPosition(int cprLat, int cprLon, boolean surface) {
31+
setLatLon(cprLat / (double) (1 << 17), cprLon / (double) (1 << 17));
32+
this.surface = surface;
33+
}
34+
2035
public void setLatLon(double lat, double lon) {
2136
this.lat = lat;
2237
this.lon = lon;
@@ -40,6 +55,34 @@ public double getLon() {
4055
return lon;
4156
}
4257

58+
public void setSurface(boolean surface) {
59+
this.surface = surface;
60+
}
61+
62+
public boolean getSurface() {
63+
return this.surface;
64+
}
65+
66+
public void setZones(double latZone, double lonZone) {
67+
this.latZone = latZone;
68+
this.lonZone = lonZone;
69+
}
70+
public void setLatZone(double zone) {
71+
this.latZone = zone;
72+
}
73+
74+
public double getLatZone() {
75+
return this.latZone;
76+
}
77+
78+
public void setLonZone(double zone) {
79+
this.lonZone = zone;
80+
}
81+
82+
public double getLonZone() {
83+
return this.lonZone;
84+
}
85+
4386
public void setTime(long time) {
4487
this.time = time;
4588
}
@@ -52,6 +95,10 @@ public boolean isValid() {
5295
return valid;
5396
}
5497

98+
public void setValid(boolean valid) {
99+
this.valid = valid;
100+
}
101+
55102
public boolean isExpired() {
56103
return time < Instant.now().minusSeconds(10).toEpochMilli();
57104
}

src/main/java/aero/t2s/modes/ModeSHandler.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package aero.t2s.modes;
22

33
import aero.t2s.modes.decoder.df.DownlinkFormat;
4-
import aero.t2s.modes.decoder.df.df17.AirbornePosition;
4+
import aero.t2s.modes.decoder.df.df17.PositionUpdate;
55

66
import java.util.function.Consumer;
77

88
abstract public class ModeSHandler {
9+
protected double originLat;
10+
protected double originLon;
911
protected Consumer<Track> onDeleted = track -> {};
1012
protected Consumer<Track> onCreated = track -> {};
1113
protected Consumer<Track> onUpdated = track -> {};
@@ -43,10 +45,10 @@ protected short[] toData(final String input) throws EmptyMessageException, ModeA
4345
}
4446

4547
public void start() {
46-
AirbornePosition.start();
48+
PositionUpdate.start(originLat, originLon);
4749
}
4850

4951
public void stop() {
50-
AirbornePosition.stop();
52+
PositionUpdate.stop();
5153
}
5254
}

src/main/java/aero/t2s/modes/ModeSMessageHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public class ModeSMessageHandler extends ModeSHandler {
2222
private Consumer<DownlinkFormat> onMessage;
2323

2424
public ModeSMessageHandler(double originLat, double originLon) {
25+
this.originLat = originLat;
26+
this.originLon = originLon;
2527
this.decoder = new Decoder(new HashMap<>(), originLat, originLon, ModeSDatabase.createDatabase());
2628
}
2729

src/main/java/aero/t2s/modes/ModeSTrackHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public class ModeSTrackHandler extends ModeSHandler {
2424

2525
public ModeSTrackHandler(Map<String, Track> tracks, double originLat, double originLon, ModeSDatabase database) {
2626
this.tracks = tracks;
27+
this.originLat = originLat;
28+
this.originLon = originLon;
2729
this.decoder = new Decoder(tracks, originLat, originLon, database);
2830

2931
timer = new Timer();

src/main/java/aero/t2s/modes/decoder/df/DF17.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public DF17 decode() {
4141
case 6:
4242
case 7:
4343
case 8:
44-
extendedSquitter = new SurfacePosition(data);
44+
extendedSquitter = new SurfacePosition(data, getIcao());
4545
break;
4646
case 19:
4747
extendedSquitter = new AirborneVelocity(data);

src/main/java/aero/t2s/modes/decoder/df/DF18.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public DF18 decode() {
2525
case 6:
2626
case 7:
2727
case 8:
28-
extendedSquitter = new SurfacePosition(data);
28+
extendedSquitter = new SurfacePosition(data, getIcao());
2929
break;
3030
case 19:
3131
extendedSquitter = new AirborneVelocity(data);

src/main/java/aero/t2s/modes/decoder/df/df17/AirbornePosition.java

Lines changed: 8 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import aero.t2s.modes.Track;
44
import aero.t2s.modes.CprPosition;
55
import aero.t2s.modes.constants.*;
6-
import aero.t2s.modes.decoder.Common;
76
import aero.t2s.modes.registers.Register05;
87
import aero.t2s.modes.registers.Register05V0;
98
import aero.t2s.modes.registers.Register05V2;
@@ -18,12 +17,9 @@ public class AirbornePosition extends ExtendedSquitter {
1817
private boolean altitudeSourceBaro;
1918
private int altitude;
2019

21-
private boolean positionAvailable;
22-
2320
private double lat;
2421
private double lon;
25-
private static Map<String, PositionUpdate> cache = new HashMap<>();
26-
private static Timer cacheCleanup;
22+
private boolean positionAvailable;
2723

2824
public AirbornePosition(short[] data, String address) {
2925
super(data);
@@ -58,39 +54,14 @@ public AirbornePosition decode() {
5854
cprLon = cprLon | (data[9] << 8);
5955
cprLon = cprLon | data[10];
6056

61-
62-
if (!cache.containsKey(address)) {
63-
if (!isCprEven) {
64-
return this;
65-
}
66-
67-
synchronized (cache) {
68-
cache.putIfAbsent(address, new PositionUpdate(
69-
new CprPosition(cprLat / (double)(1 << 17), cprLon / (double)(1 << 17))
70-
));
71-
}
72-
}
73-
74-
PositionUpdate positionUpdate;
75-
synchronized (cache) {
76-
positionUpdate = cache.get(address);
77-
}
78-
if (isCprEven) {
79-
positionUpdate.setEven(new CprPosition(cprLat / (double) (1 << 17), cprLon / (double) (1 << 17)));
80-
} else {
81-
positionUpdate.setOdd(new CprPosition(cprLat / (double) (1 << 17), cprLon / (double) (1 << 17)));
82-
}
83-
84-
if (positionUpdate.isComplete()) {
85-
calculateGlobal(positionUpdate.even, positionUpdate.odd);
86-
} else if (positionUpdate.isPreviousPositionAvailable() && positionUpdate.isPreviousPositionAvailable()) {
87-
calculateLocal(positionUpdate.odd, true, positionUpdate.previousLat, positionUpdate.previousLon);
88-
}
89-
90-
if (positionAvailable) {
91-
positionUpdate.setPreviousPosition(this.lat, this.lon);
57+
CprPosition newPosition = PositionUpdate.calculate(address, isCprEven, new CprPosition(cprLat, cprLon, false));
58+
if (newPosition != null) {
59+
this.lat = newPosition.getLat();
60+
this.lon = newPosition.getLon();
61+
this.positionAvailable = true;
62+
} else {
63+
this.positionAvailable = false;
9264
}
93-
9465
return this;
9566
}
9667

@@ -230,88 +201,6 @@ private AltitudeSource determineAltitudeSource() {
230201
return AltitudeSource.GNSS_HAE;
231202
}
232203

233-
private void calculateLocal(CprPosition cpr, boolean isOdd, double previousLat, double previousLon) {
234-
235-
double dlat = isOdd ? 360.0 / 59.0 : 360.0 / 60.0;
236-
237-
double j = Math.floor(previousLat / dlat) + Math.floor((previousLat % dlat) / dlat - cpr.getLat() + 0.5);
238-
239-
double newLat = dlat * (j + previousLat);
240-
241-
double nl = NL(newLat) - (isOdd ? 1.0 : 0.0);
242-
double dlon = nl > 0 ? 360.0 / nl : 360;
243-
244-
double m = Math.floor(previousLon / dlon) + Math.floor((previousLon % dlon) / dlon - cpr.getLon() + 0.5);
245-
double newLon = dlon * (m + lon);
246-
247-
//TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range
248-
//TODO Should be a sanity-check here to see if the calculated movement since the last update is too far
249-
this.lat = newLat;
250-
this.lon = newLon;
251-
this.positionAvailable = true;
252-
}
253-
254-
private void calculateGlobal(CprPosition cprEven, CprPosition cprOdd) {
255-
double dLat0 = 360.0 / 60.0;
256-
double dLat1 = 360.0 / 59.0;
257-
258-
double j = Math.floor(59.0 * cprEven.getLat() - 60.0 * cprOdd.getLat() + 0.5);
259-
260-
double latEven = dLat0 * (j % 60.0 + cprEven.getLat());
261-
double latOdd = dLat1 * (j % 59.0 + cprOdd.getLat());
262-
263-
if (latEven >= 270.0 && latEven <= 360.0) {
264-
latEven -= 360.0;
265-
}
266-
267-
if (latOdd >= 270.0 && latOdd <= 360.0) {
268-
latOdd -= 360.0;
269-
}
270-
271-
if (NL(latEven) != NL(latOdd)) {
272-
return;
273-
}
274-
275-
double lat;
276-
double lon;
277-
if (cprEven.getTime() > cprOdd.getTime()) {
278-
double ni = cprN(latEven, 0);
279-
double m = Math.floor(cprEven.getLon() * (NL(latEven) - 1) - cprOdd.getLon() * NL(latEven) + 0.5);
280-
281-
lat = latEven;
282-
lon = (360d / ni) * (m % ni + cprEven.getLon());
283-
} else {
284-
double ni = cprN(latOdd, 1);
285-
double m = Math.floor(cprEven.getLon() * (NL(latOdd) - 1) - cprOdd.getLon() * NL(latOdd) + 0.5);
286-
287-
lat = latOdd;
288-
lon = (360d / ni) * (m % ni + cprOdd.getLon());
289-
}
290-
291-
if (lon > 180d) {
292-
lon -= 360d;
293-
}
294-
295-
//TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range,
296-
this.lat = lat;
297-
this.lon = lon;
298-
this.positionAvailable = true;
299-
}
300-
private double cprN(double lat, double isOdd) {
301-
double nl = NL(lat) - isOdd;
302-
303-
return nl > 1 ? nl : 1;
304-
}
305-
306-
private double NL(double lat) {
307-
if (lat == 0) return 59;
308-
else if (Math.abs(lat) == 87) return 2;
309-
else if (Math.abs(lat) > 87) return 1;
310-
311-
double tmp = 1 - (1 - Math.cos(Math.PI / (2.0 * 15.0))) / Math.pow(Math.cos(Math.PI / 180.0 * Math.abs(lat)), 2);
312-
return Math.floor(2 * Math.PI / Math.acos(tmp));
313-
}
314-
315204
private int calculateAltitude(short[] data, int typeCode) {
316205
// TODO this should use AltitudeEncoding class flagged with mBit false feature.
317206
int n = (data[5] >>> 1) << 4;
@@ -321,66 +210,4 @@ private int calculateAltitude(short[] data, int typeCode) {
321210

322211
return (n * qBit) - 1000;
323212
}
324-
325-
public static void start() {
326-
AirbornePosition.cache.clear();
327-
AirbornePosition.cacheCleanup.schedule(new TimerTask() {
328-
@Override
329-
public void run() {
330-
List<String> expired = new LinkedList<>();
331-
332-
synchronized (cache) {
333-
cache.entrySet().stream().filter(entry -> entry.getValue().isExpired()).forEach(entry -> expired.add(entry.getKey()));
334-
expired.forEach(cache::remove);
335-
}
336-
}
337-
}, 0, 10_000);
338-
}
339-
340-
public static void stop() {
341-
AirbornePosition.cacheCleanup.cancel();
342-
AirbornePosition.cacheCleanup = null;
343-
344-
AirbornePosition.cache.clear();
345-
}
346-
347-
class PositionUpdate {
348-
private CprPosition even;
349-
private CprPosition odd;
350-
351-
352-
private boolean previousPositionAvailable = false;
353-
private double previousLat;
354-
private double previousLon;
355-
356-
public PositionUpdate(CprPosition even) {
357-
this.even = even;
358-
}
359-
360-
public void setEven(CprPosition even) {
361-
this.even = even;
362-
this.odd = null;
363-
}
364-
365-
public void setOdd(CprPosition odd) {
366-
this.odd = odd;
367-
}
368-
369-
public void setPreviousPosition(double lat, double lon) {
370-
this.previousLat = lat;
371-
this.previousLon = lon;
372-
}
373-
374-
public boolean isPreviousPositionAvailable() {
375-
return this.previousPositionAvailable;
376-
}
377-
378-
public boolean isComplete() {
379-
return even != null && odd != null;
380-
}
381-
382-
public boolean isExpired() {
383-
return even.isExpired() || odd.isExpired();
384-
}
385-
}
386213
}

0 commit comments

Comments
 (0)