33import aero .t2s .modes .Track ;
44import aero .t2s .modes .CprPosition ;
55import aero .t2s .modes .constants .*;
6+ import aero .t2s .modes .decoder .Common ;
67import aero .t2s .modes .registers .Register05 ;
78import aero .t2s .modes .registers .Register05V0 ;
89import aero .t2s .modes .registers .Register05V2 ;
910
10- public class AirbornePosition extends ExtendedSquitter {
11- private final double originLat ;
12- private final double originLon ;
11+ import java .util .*;
1312
13+ public class AirbornePosition extends ExtendedSquitter {
14+ private final String address ;
1415 private SurveillanceStatus surveillanceStatus ;
1516 private int singleAntennaFlag ;
1617
@@ -19,16 +20,14 @@ public class AirbornePosition extends ExtendedSquitter {
1920
2021 private boolean positionAvailable ;
2122
22- private CprPosition cprEven = new CprPosition ();
23- private CprPosition cprOdd = new CprPosition ();
24-
2523 private double lat ;
2624 private double lon ;
25+ private static Map <String , PositionUpdate > cache = new HashMap <>();
26+ private static Timer cacheCleanup ;
2727
28- public AirbornePosition (short [] data , final double originLat , final double originLon ) {
28+ public AirbornePosition (short [] data , String address ) {
2929 super (data );
30- this .originLat = originLat ;
31- this .originLon = originLon ;
30+ this .address = address ;
3231 }
3332
3433 @ Override
@@ -59,14 +58,38 @@ public AirbornePosition decode() {
5958 cprLon = cprLon | (data [9 ] << 8 );
6059 cprLon = cprLon | data [10 ];
6160
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+ }
6278 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 ));
6482 }
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 );
6788 }
6889
69- calculatePosition (isCprEven );
90+ if (positionAvailable ) {
91+ positionUpdate .setPreviousPosition (this .lat , this .lon );
92+ }
7093
7194 return this ;
7295 }
@@ -77,9 +100,9 @@ public void apply(Track track) {
77100 track .setSpi (surveillanceStatus == SurveillanceStatus .SPI );
78101 track .setTempAlert (surveillanceStatus == SurveillanceStatus .TEMPORARY_ALERT );
79102 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+ }
83106
84107 if (versionChanged (track )) {
85108 switch (track .getVersion ()) {
@@ -130,14 +153,6 @@ public BarometricAltitudeIntegrityCode getNICbaro() {
130153 }
131154 }
132155
133- public double getOriginLat () {
134- return originLat ;
135- }
136-
137- public double getOriginLon () {
138- return originLon ;
139- }
140-
141156 public SurveillanceStatus getSurveillanceStatus () {
142157 return surveillanceStatus ;
143158 }
@@ -215,25 +230,6 @@ private AltitudeSource determineAltitudeSource() {
215230 return AltitudeSource .GNSS_HAE ;
216231 }
217232
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-
237233 private void calculateLocal (CprPosition cpr , boolean isOdd , double previousLat , double previousLon ) {
238234
239235 double dlat = isOdd ? 360.0 / 59.0 : 360.0 / 60.0 ;
@@ -298,6 +294,7 @@ private void calculateGlobal(CprPosition cprEven, CprPosition cprOdd) {
298294 //TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range,
299295 this .lat = lat ;
300296 this .lon = lon ;
297+ this .positionAvailable = true ;
301298 }
302299 private double cprN (double lat , double isOdd ) {
303300 double nl = NL (lat ) - isOdd ;
@@ -323,4 +320,66 @@ private int calculateAltitude(short[] data, int typeCode) {
323320
324321 return (n * qBit ) - 1000 ;
325322 }
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+ }
326385}
0 commit comments