3
3
import aero .t2s .modes .Track ;
4
4
import aero .t2s .modes .CprPosition ;
5
5
import aero .t2s .modes .constants .*;
6
+ import aero .t2s .modes .decoder .Common ;
6
7
import aero .t2s .modes .registers .Register05 ;
7
8
import aero .t2s .modes .registers .Register05V0 ;
8
9
import aero .t2s .modes .registers .Register05V2 ;
9
10
10
- public class AirbornePosition extends ExtendedSquitter {
11
- private final double originLat ;
12
- private final double originLon ;
11
+ import java .util .*;
13
12
13
+ public class AirbornePosition extends ExtendedSquitter {
14
+ private final String address ;
14
15
private SurveillanceStatus surveillanceStatus ;
15
16
private int singleAntennaFlag ;
16
17
@@ -19,16 +20,14 @@ public class AirbornePosition extends ExtendedSquitter {
19
20
20
21
private boolean positionAvailable ;
21
22
22
- private CprPosition cprEven = new CprPosition ();
23
- private CprPosition cprOdd = new CprPosition ();
24
-
25
23
private double lat ;
26
24
private double lon ;
25
+ private static Map <String , PositionUpdate > cache = new HashMap <>();
26
+ private static Timer cacheCleanup ;
27
27
28
- public AirbornePosition (short [] data , final double originLat , final double originLon ) {
28
+ public AirbornePosition (short [] data , String address ) {
29
29
super (data );
30
- this .originLat = originLat ;
31
- this .originLon = originLon ;
30
+ this .address = address ;
32
31
}
33
32
34
33
@ Override
@@ -59,14 +58,38 @@ public AirbornePosition decode() {
59
58
cprLon = cprLon | (data [9 ] << 8 );
60
59
cprLon = cprLon | data [10 ];
61
60
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
+ }
62
78
if (isCprEven ) {
63
- this .cprEven .setLatLon (cprLat /(double )(1 << 17 ), cprLon /(double )(1 << 17 ));
79
+ positionUpdate .setEven (new CprPosition (cprLat / (double ) (1 << 17 ), cprLon / (double ) (1 << 17 )));
80
+ } else {
81
+ positionUpdate .setOdd (new CprPosition (cprLat , cprLon ));
64
82
}
65
- else {
66
- this .cprOdd .setLatLon (cprLat , cprLon );
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 );
67
88
}
68
89
69
- calculatePosition (isCprEven );
90
+ if (positionAvailable ) {
91
+ positionUpdate .setPreviousPosition (this .lat , this .lon );
92
+ }
70
93
71
94
return this ;
72
95
}
@@ -77,9 +100,9 @@ public void apply(Track track) {
77
100
track .setSpi (surveillanceStatus == SurveillanceStatus .SPI );
78
101
track .setTempAlert (surveillanceStatus == SurveillanceStatus .TEMPORARY_ALERT );
79
102
track .setEmergency (surveillanceStatus == SurveillanceStatus .PERMANENT_ALERT );
80
- track . setCprEven ( cprEven );
81
- track .setCprOdd ( cprOdd );
82
- track . setLatLon ( lat , lon );
103
+ if ( positionAvailable ) {
104
+ track .setLatLon ( lat , lon );
105
+ }
83
106
84
107
if (versionChanged (track )) {
85
108
switch (track .getVersion ()) {
@@ -130,14 +153,6 @@ public BarometricAltitudeIntegrityCode getNICbaro() {
130
153
}
131
154
}
132
155
133
- public double getOriginLat () {
134
- return originLat ;
135
- }
136
-
137
- public double getOriginLon () {
138
- return originLon ;
139
- }
140
-
141
156
public SurveillanceStatus getSurveillanceStatus () {
142
157
return surveillanceStatus ;
143
158
}
@@ -215,25 +230,6 @@ private AltitudeSource determineAltitudeSource() {
215
230
return AltitudeSource .GNSS_HAE ;
216
231
}
217
232
218
- private void calculatePosition (boolean isEven ) {
219
- if (!positionAvailable ) {
220
- //TODO Could be other cases where we need to do global calculation, such as too much time elapsed since last position update
221
- calculateGlobal (cprEven , cprOdd );
222
- positionAvailable = true ;
223
- }
224
- else {
225
- if (isEven ) {
226
- if (cprOdd .isValid ()) {
227
- calculateLocal (cprEven , false , this .lat , this .lon );
228
- }
229
- } else {
230
- if (cprEven .isValid ()) {
231
- calculateLocal (cprOdd , true , this .lat , this .lon );
232
- }
233
- }
234
- }
235
- }
236
-
237
233
private void calculateLocal (CprPosition cpr , boolean isOdd , double previousLat , double previousLon ) {
238
234
239
235
double dlat = isOdd ? 360.0 / 59.0 : 360.0 / 60.0 ;
@@ -298,6 +294,7 @@ private void calculateGlobal(CprPosition cprEven, CprPosition cprOdd) {
298
294
//TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range,
299
295
this .lat = lat ;
300
296
this .lon = lon ;
297
+ this .positionAvailable = true ;
301
298
}
302
299
private double cprN (double lat , double isOdd ) {
303
300
double nl = NL (lat ) - isOdd ;
@@ -323,4 +320,66 @@ private int calculateAltitude(short[] data, int typeCode) {
323
320
324
321
return (n * qBit ) - 1000 ;
325
322
}
323
+
324
+ public static void start () {
325
+ AirbornePosition .cache .clear ();
326
+ AirbornePosition .cacheCleanup .schedule (new TimerTask () {
327
+ @ Override
328
+ public void run () {
329
+ List <String > expired = new LinkedList <>();
330
+
331
+ synchronized (cache ) {
332
+ cache .entrySet ().stream ().filter (entry -> entry .getValue ().isExpired ()).forEach (entry -> expired .add (entry .getKey ()));
333
+ expired .forEach (cache ::remove );
334
+ }
335
+ }
336
+ }, 0 , 10_000 );
337
+ }
338
+
339
+ public static void stop () {
340
+ AirbornePosition .cacheCleanup .cancel ();
341
+ AirbornePosition .cacheCleanup = null ;
342
+
343
+ AirbornePosition .cache .clear ();
344
+ }
345
+
346
+ class PositionUpdate {
347
+ private CprPosition even ;
348
+ private CprPosition odd ;
349
+
350
+
351
+ private boolean previousPositionAvailable = false ;
352
+ private double previousLat ;
353
+ private double previousLon ;
354
+
355
+ public PositionUpdate (CprPosition even ) {
356
+ this .even = even ;
357
+ }
358
+
359
+ public void setEven (CprPosition even ) {
360
+ this .even = even ;
361
+ this .odd = null ;
362
+ }
363
+
364
+ public void setOdd (CprPosition odd ) {
365
+ this .odd = odd ;
366
+ }
367
+
368
+ public void setPreviousPosition (double lat , double lon ) {
369
+ this .previousLat = lat ;
370
+ this .previousLon = lon ;
371
+ }
372
+
373
+ public boolean isPreviousPositionAvailable () {
374
+ return this .previousPositionAvailable ;
375
+ }
376
+
377
+ public boolean isComplete () {
378
+ return even != null && odd != null ;
379
+ }
380
+
381
+ public boolean isExpired () {
382
+ return even .isExpired () || odd .isExpired ();
383
+ }
384
+ }
326
385
}
0 commit comments