33import aero .t2s .modes .Track ;
44import aero .t2s .modes .CprPosition ;
55import aero .t2s .modes .constants .*;
6- import aero .t2s .modes .decoder .Common ;
76import aero .t2s .modes .registers .Register05 ;
87import aero .t2s .modes .registers .Register05V0 ;
98import 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