interactive.c
Go to the documentation of this file.
1 // dump1090, a Mode S messages decoder for RTLSDR devices.
2 //
3 // Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are
9 // met:
10 //
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 
31 #include "dump1090.h"
32 //
33 // ============================= Utility functions ==========================
34 //
35 static uint64_t mstime(void) {
36  struct timeval tv;
37  uint64_t mst;
38 
39  gettimeofday(&tv, NULL);
40  mst = ((uint64_t)tv.tv_sec)*1000;
41  mst += tv.tv_usec/1000;
42  return mst;
43 }
44 //
45 //========================= Interactive mode ===============================
46 //
47 // Return a new aircraft structure for the interactive mode linked list
48 // of aircraft
49 //
51  struct aircraft *a = (struct aircraft *) malloc(sizeof(*a));
52 
53  // Default everything to zero/NULL
54  memset(a, 0, sizeof(*a));
55 
56  // Now initialise things that should not be 0/NULL to their defaults
57  a->addr = mm->addr;
58  a->lat = a->lon = 0.0;
59  memset(a->signalLevel, mm->signalLevel, 8); // First time, initialise everything
60  // to the first signal strength
61 
62  // mm->msgtype 32 is used to represent Mode A/C. These values can never change, so
63  // set them once here during initialisation, and don't bother to set them every
64  // time this ModeA/C is received again in the future
65  if (mm->msgtype == 32) {
66  int modeC = ModeAToModeC(mm->modeA | mm->fs);
68  if (modeC < -12) {
70  } else {
71  mm->altitude = modeC * 100;
73  }
74  }
75  return (a);
76 }
77 //
78 //=========================================================================
79 //
80 // Return the aircraft with the specified address, or NULL if no aircraft
81 // exists with this address.
82 //
84  struct aircraft *a = Modes.aircrafts;
85 
86  while(a) {
87  if (a->addr == addr) return (a);
88  a = a->next;
89  }
90  return (NULL);
91 }
92 //
93 //=========================================================================
94 //
95 // We have received a Mode A or C response.
96 //
97 // Search through the list of known Mode-S aircraft and tag them if this Mode A/C
98 // matches their known Mode S Squawks or Altitudes(+/- 50feet).
99 //
100 // A Mode S equipped aircraft may also respond to Mode A and Mode C SSR interrogations.
101 // We can't tell if this is a Mode A or C, so scan through the entire aircraft list
102 // looking for matches on Mode A (squawk) and Mode C (altitude). Flag in the Mode S
103 // records that we have had a potential Mode A or Mode C response from this aircraft.
104 //
105 // If an aircraft responds to Mode A then it's highly likely to be responding to mode C
106 // too, and vice verca. Therefore, once the mode S record is tagged with both a Mode A
107 // and a Mode C flag, we can be fairly confident that this Mode A/C frame relates to that
108 // Mode S aircraft.
109 //
110 // Mode C's are more likely to clash than Mode A's; There could be several aircraft
111 // cruising at FL370, but it's less likely (though not impossible) that there are two
112 // aircraft on the same squawk. Therefore, give precidence to Mode A record matches
113 //
114 // Note : It's theoretically possible for an aircraft to have the same value for Mode A
115 // and Mode C. Therefore we have to check BOTH A AND C for EVERY S.
116 //
118  struct aircraft *b = Modes.aircrafts;
119 
120  while(b) {
121  if ((b->modeACflags & MODEAC_MSG_FLAG) == 0) {// skip any fudged ICAO records
122 
123  // If both (a) and (b) have valid squawks...
124  if ((a->bFlags & b->bFlags) & MODES_ACFLAGS_SQUAWK_VALID) {
125  // ...check for Mode-A == Mode-S Squawk matches
126  if (a->modeA == b->modeA) { // If a 'real' Mode-S ICAO exists using this Mode-A Squawk
127  b->modeAcount = a->messages;
130  if ( (b->modeAcount > 0) &&
131  ( (b->modeCcount > 1)
132  || (a->modeACflags & MODEAC_MSG_MODEA_ONLY)) ) // Allow Mode-A only matches if this Mode-A is invalid Mode-C
133  {a->modeACflags |= MODEAC_MSG_MODES_HIT;} // flag this ModeA/C probably belongs to a known Mode S
134  }
135  }
136 
137  // If both (a) and (b) have valid altitudes...
138  if ((a->bFlags & b->bFlags) & MODES_ACFLAGS_ALTITUDE_VALID) {
139  // ... check for Mode-C == Mode-S Altitude matches
140  if ( (a->modeC == b->modeC ) // If a 'real' Mode-S ICAO exists at this Mode-C Altitude
141  || (a->modeC == b->modeC + 1) // or this Mode-C - 100 ft
142  || (a->modeC + 1 == b->modeC ) ) { // or this Mode-C + 100 ft
143  b->modeCcount = a->messages;
146  if ( (b->modeAcount > 0) &&
147  (b->modeCcount > 1) )
148  {a->modeACflags |= (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEC_OLD);} // flag this ModeA/C probably belongs to a known Mode S
149  }
150  }
151  }
152  b = b->next;
153  }
154 }
155 //
156 //=========================================================================
157 //
159  struct aircraft *a = Modes.aircrafts;
160 
161  while(a) {
162  int flags = a->modeACflags;
163  if (flags & MODEAC_MSG_FLAG) { // find any fudged ICAO records
164 
165  // clear the current A,C and S hit bits ready for this attempt
167 
168  interactiveUpdateAircraftModeA(a); // and attempt to match them with Mode-S
169  }
170  a = a->next;
171  }
172 }
173 //
174 //=========================================================================
175 //
176 // Receive new messages and populate the interactive mode with more info
177 //
179  struct aircraft *a, *aux;
180 
181  // Return if (checking crc) AND (not crcok) AND (not fixed)
182  if (Modes.check_crc && (mm->crcok == 0) && (mm->correctedbits == 0))
183  return NULL;
184 
185  // Lookup our aircraft or create a new one
186  a = interactiveFindAircraft(mm->addr);
187  if (!a) { // If it's a currently unknown aircraft....
188  a = interactiveCreateAircraft(mm); // ., create a new record for it,
189  a->next = Modes.aircrafts; // .. and put it at the head of the list
190  Modes.aircrafts = a;
191  } else {
192  /* If it is an already known aircraft, move it on head
193  * so we keep aircrafts ordered by received message time.
194  *
195  * However move it on head only if at least one second elapsed
196  * since the aircraft that is currently on head sent a message,
197  * othewise with multiple aircrafts at the same time we have an
198  * useless shuffle of positions on the screen. */
199  if (0 && Modes.aircrafts != a && (time(NULL) - a->seen) >= 1) {
200  aux = Modes.aircrafts;
201  while(aux->next != a) aux = aux->next;
202  /* Now we are a node before the aircraft to remove. */
203  aux->next = aux->next->next; /* removed. */
204  /* Add on head */
205  a->next = Modes.aircrafts;
206  Modes.aircrafts = a;
207  }
208  }
209 
210  a->signalLevel[a->messages & 7] = mm->signalLevel;// replace the 8th oldest signal strength
211  a->seen = time(NULL);
212  a->timestamp = mm->timestampMsg;
213  a->messages++;
214 
215  // If a (new) CALLSIGN has been received, copy it to the aircraft structure
217  memcpy(a->flight, mm->flight, sizeof(a->flight));
218  }
219 
220  // If a (new) ALTITUDE has been received, copy it to the aircraft structure
222  if ( (a->modeCcount) // if we've a modeCcount already
223  && (a->altitude != mm->altitude ) ) // and Altitude has changed
224 // && (a->modeC != mm->modeC + 1) // and Altitude not changed by +100 feet
225 // && (a->modeC + 1 != mm->modeC ) ) // and Altitude not changes by -100 feet
226  {
227  a->modeCcount = 0; //....zero the hit count
229  }
230  a->altitude = mm->altitude;
231  a->modeC = (mm->altitude + 49) / 100;
232  }
233 
234  // If a (new) SQUAWK has been received, copy it to the aircraft structure
236  if (a->modeA != mm->modeA) {
237  a->modeAcount = 0; // Squawk has changed, so zero the hit count
239  }
240  a->modeA = mm->modeA;
241  }
242 
243  // If a (new) HEADING has been received, copy it to the aircraft structure
245  a->track = mm->heading;
246  }
247 
248  // If a (new) SPEED has been received, copy it to the aircraft structure
249  if (mm->bFlags & MODES_ACFLAGS_SPEED_VALID) {
250  a->speed = mm->velocity;
251  }
252 
253  // If a (new) Vertical Descent rate has been received, copy it to the aircraft structure
255  a->vert_rate = mm->vert_rate;
256  }
257 
258  // if the Aircraft has landed or taken off since the last message, clear the even/odd CPR flags
259  if ((mm->bFlags & MODES_ACFLAGS_AOG_VALID) && ((a->bFlags ^ mm->bFlags) & MODES_ACFLAGS_AOG)) {
261  }
262 
263  // If we've got a new cprlat or cprlon
265 
266  if (mm->bFlags & MODES_ACFLAGS_LLODD_VALID) {
267  a->odd_cprlat = mm->raw_latitude;
268  a->odd_cprlon = mm->raw_longitude;
269  a->odd_cprtime = mstime();
270  } else {
271  a->even_cprlat = mm->raw_latitude;
272  a->even_cprlon = mm->raw_longitude;
273  a->even_cprtime = mstime();
274  }
275 
277  // If we now have both even and odd, decode the CPR
278 
279  // Try relative CPR first
280  if (decodeCPRrelative(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG))) {
281  // If relative CPR fails then try global if the two data are less than 10 seconds apart
282  if (abs((int)(a->even_cprtime - a->odd_cprtime)) <= 10000) {
283  decodeCPR(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG));
284  }
285  }
286 
287  //If we sucessfully decoded, back copy the results to mm so that we can print them in list output
290  mm->fLat = a->lat;
291  mm->fLon = a->lon;
292  }
293  }
294  }
295 
296  // Update the aircrafts a->bFlags to reflect the newly received mm->bFlags;
297  a->bFlags |= mm->bFlags;
298 
299  if (mm->msgtype == 32) {
300  int flags = a->modeACflags;
302  //
303  // This Mode-C doesn't currently hit any known Mode-S, but it used to because MODEAC_MSG_MODEC_OLD is
304  // set So the aircraft it used to match has either changed altitude, or gone out of our receiver range
305  //
306  // We've now received this Mode-A/C again, so it must be a new aircraft. It could be another aircraft
307  // at the same Mode-C altitude, or it could be a new airctraft with a new Mods-A squawk.
308  //
309  // To avoid masking this aircraft from the interactive display, clear the MODEAC_MSG_MODES_OLD flag
310  // and set messages to 1;
311  //
312  a->modeACflags = flags & ~MODEAC_MSG_MODEC_OLD;
313  a->messages = 1;
314  }
315  }
316 
317  return (a);
318 }
319 //
320 //=========================================================================
321 //
322 // Show the currently captured interactive data on screen.
323 //
325  struct aircraft *a = Modes.aircrafts;
326  time_t now = time(NULL);
327  int count = 0;
328  char progress;
329  char spinner[4] = "|/-\\";
330 
331  // Refresh screen every (MODES_INTERACTIVE_REFRESH_TIME) miliseconde
332  if ((mstime() - Modes.interactive_last_update) < MODES_INTERACTIVE_REFRESH_TIME)
333  {return;}
334 
335  Modes.interactive_last_update = mstime();
336 
337  // Attempt to reconsile any ModeA/C with known Mode-S
338  // We can't condition on Modes.modeac because ModeA/C could be comming
339  // in from a raw input port which we can't turn off.
341 
342  progress = spinner[time(NULL)%4];
343 
344 #ifndef _WIN32
345  printf("\x1b[H\x1b[2J"); // Clear the screen
346 #else
347  cls();
348 #endif
349 
350  if (Modes.interactive_rtl1090 == 0) {
351  printf (
352 "Hex Mode Sqwk Flight Alt Spd Hdg Lat Long Sig Msgs Ti%c\n", progress);
353  } else {
354  printf (
355 "Hex Flight Alt V/S GS TT SSR G*456^ Msgs Seen %c\n", progress);
356  }
357  printf(
358 "-------------------------------------------------------------------------------\n");
359 
360  while(a && (count < Modes.interactive_rows)) {
361 
362  if ((now - a->seen) < Modes.interactive_display_ttl)
363  {
364  int msgs = a->messages;
365  int flags = a->modeACflags;
366 
367  if ( (((flags & (MODEAC_MSG_FLAG )) == 0 ) )
368  || (((flags & (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEA_ONLY)) == MODEAC_MSG_MODEA_ONLY) && (msgs > 4 ) )
369  || (((flags & (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEC_OLD )) == 0 ) && (msgs > 127) )
370  ) {
371  int altitude = a->altitude, speed = a->speed;
372  char strSquawk[5] = " ";
373  char strFl[6] = " ";
374  char strTt[5] = " ";
375  char strGs[5] = " ";
376 
377  // Convert units to metric if --metric was specified
378  if (Modes.metric) {
379  altitude = (int) (altitude / 3.2828);
380  speed = (int) (speed * 1.852);
381  }
382 
384  snprintf(strSquawk,5,"%04x", a->modeA);}
385 
387  snprintf (strGs, 5,"%3d", speed);}
388 
390  snprintf (strTt, 5,"%03d", a->track);}
391 
392  if (msgs > 99999) {
393  msgs = 99999;}
394 
395  if (Modes.interactive_rtl1090) { // RTL1090 display mode
396 
398  snprintf(strFl,6,"F%03d",(altitude/100));
399  }
400  printf("%06x %-8s %-4s %-3s %-3s %4s %-6d %-2d\n",
401  a->addr, a->flight, strFl, strGs, strTt, strSquawk, msgs, (int)(now - a->seen));
402 
403  } else { // Dump1090 display mode
404  char strMode[5] = " ";
405  char strLat[8] = " ";
406  char strLon[9] = " ";
407  unsigned char * pSig = a->signalLevel;
408  unsigned int signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
409  pSig[4] + pSig[5] + pSig[6] + pSig[7] + 3) >> 3;
410 
411  if ((flags & MODEAC_MSG_FLAG) == 0) {
412  strMode[0] = 'S';
413  } else if (flags & MODEAC_MSG_MODEA_ONLY) {
414  strMode[0] = 'A';
415  }
416  if (flags & MODEAC_MSG_MODEA_HIT) {strMode[2] = 'a';}
417  if (flags & MODEAC_MSG_MODEC_HIT) {strMode[3] = 'c';}
418 
420  snprintf(strLat, 8,"%7.03f", a->lat);
421  snprintf(strLon, 9,"%8.03f", a->lon);
422  }
423 
424  if (a->bFlags & MODES_ACFLAGS_AOG) {
425  snprintf(strFl, 6," grnd");
426  } else if (a->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) {
427  snprintf(strFl, 6, "%5d", altitude);
428  }
429 
430  printf("%06x %-4s %-4s %-8s %5s %3s %3s %7s %8s %3d %5d %2d\n",
431  a->addr, strMode, strSquawk, a->flight, strFl, strGs, strTt,
432  strLat, strLon, signalAverage, msgs, (int)(now - a->seen));
433  }
434  count++;
435  }
436  }
437  a = a->next;
438  }
439 }
440 //
441 //=========================================================================
442 //
443 // When in interactive mode If we don't receive new nessages within
444 // MODES_INTERACTIVE_DELETE_TTL seconds we remove the aircraft from the list.
445 //
447  struct aircraft *a = Modes.aircrafts;
448  struct aircraft *prev = NULL;
449  time_t now = time(NULL);
450 
451  while(a) {
452  if ((now - a->seen) > Modes.interactive_delete_ttl) {
453  struct aircraft *next = a->next;
454  // Remove the element from the linked list, with care
455  // if we are removing the first element
456 
457  if (!prev)
458  Modes.aircrafts = next;
459  else
460  prev->next = next;
461 
462  free(a);
463  a = next;
464  } else {
465  prev = a;
466  a = a->next;
467  }
468  }
469 }
470 //
471 //=========================================================================
472 //
int ModeAToModeC(unsigned int ModeA)
Definition: mode_ac.c:319
void interactiveUpdateAircraftModeS()
Definition: interactive.c:158
long messages
Definition: dump1090.h:204
void interactiveRemoveStaleAircrafts(void)
Definition: interactive.c:446
int modeC
Definition: dump1090.h:206
int modeA
Definition: dump1090.h:205
constexpr double mm
Definition: AugerUnits.h:113
#define MODES_ACFLAGS_ALTITUDE_VALID
Definition: dump1090.h:128
int track
Definition: dump1090.h:198
uint64_t even_cprtime
Definition: dump1090.h:217
#define MODES_INTERACTIVE_REFRESH_TIME
Definition: dump1090.h:160
uint32_t addr
Definition: dump1090.h:193
int correctedbits
Definition: dump1090.h:351
int raw_longitude
Definition: dump1090.h:368
uint64_t odd_cprtime
Definition: dump1090.h:216
int altitude
Definition: dump1090.h:196
char flight[16]
Definition: dump1090.h:194
void interactiveShowData(void)
Definition: interactive.c:324
uint64_t mstime(void)
Definition: aera.c:12
uint32_t addr
Definition: dump1090.h:353
#define MODEAC_MSG_MODEA_HIT
Definition: dump1090.h:99
int even_cprlon
Definition: dump1090.h:215
int vert_rate
Definition: dump1090.h:374
void interactiveUpdateAircraftModeA(struct aircraft *a)
Definition: interactive.c:117
char flight[16]
Definition: dump1090.h:371
#define MODEAC_MSG_MODEC_HIT
Definition: dump1090.h:100
long modeAcount
Definition: dump1090.h:207
#define MODEAC_MSG_MODEA_ONLY
Definition: dump1090.h:101
uint64_t timestampMsg
Definition: dump1090.h:355
int modeACflags
Definition: dump1090.h:209
#define MODES_ACFLAGS_AOG
Definition: dump1090.h:136
struct aircraft * interactiveFindAircraft(uint32_t addr)
Definition: interactive.c:83
int odd_cprlon
Definition: dump1090.h:213
unsigned char signalLevel
Definition: dump1090.h:357
Iterator next(Iterator it)
#define MODES_ACFLAGS_LLEITHER_VALID
Definition: dump1090.h:144
int odd_cprlat
Definition: dump1090.h:212
#define MODEAC_MSG_MODEC_OLD
Definition: dump1090.h:102
double fLon
Definition: dump1090.h:370
#define MODES_ACFLAGS_SPEED_VALID
Definition: dump1090.h:130
double fLat
Definition: dump1090.h:369
struct aircraft * next
Definition: dump1090.h:220
#define MODES_ACFLAGS_SQUAWK_VALID
Definition: dump1090.h:132
struct @0 Modes
double abs(const SVector< n, T > &v)
void decodeCPR(struct aircraft *a, int fflag, int surface)
Definition: mode_s.c:1956
#define MODES_ACFLAGS_HEADING_VALID
Definition: dump1090.h:129
struct aircraft * interactiveReceiveData(struct modesMessage *mm)
Definition: interactive.c:178
int vert_rate
Definition: dump1090.h:199
#define MODES_ACFLAGS_LATLON_VALID
Definition: dump1090.h:127
#define MODES_ACFLAGS_LLBOTH_VALID
Definition: dump1090.h:145
uint64_t timestamp
Definition: dump1090.h:202
int bFlags
Definition: dump1090.h:219
unsigned char signalLevel[8]
Definition: dump1090.h:195
int decodeCPRrelative(struct aircraft *a, int fflag, int surface)
Definition: mode_s.c:2021
double lon
Definition: dump1090.h:218
int velocity
Definition: dump1090.h:375
#define MODES_ACFLAGS_LLODD_VALID
Definition: dump1090.h:138
double lat
Definition: dump1090.h:218
#define MODES_ACFLAGS_VERTRATE_VALID
Definition: dump1090.h:131
#define MODEAC_MSG_FLAG
Definition: dump1090.h:97
#define MODEAC_MSG_MODES_HIT
Definition: dump1090.h:98
time_t seen
Definition: dump1090.h:200
#define MODES_ACFLAGS_AOG_VALID
Definition: dump1090.h:139
int altitude
Definition: dump1090.h:382
#define MODES_ACFLAGS_CALLSIGN_VALID
Definition: dump1090.h:133
struct aircraft * interactiveCreateAircraft(struct modesMessage *mm)
Definition: interactive.c:50
int raw_latitude
Definition: dump1090.h:367
long modeCcount
Definition: dump1090.h:208
int speed
Definition: dump1090.h:197
int even_cprlat
Definition: dump1090.h:214

, generated on Tue Sep 26 2023.