dump1090.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 #include "coaa.h"
31 #include "dump1090.h"
32 #include "aera.h"
33 //
34 // ============================= Utility functions ==========================
35 //
36 void sigintHandler(int dummy) {
37  MODES_NOTUSED(dummy);
38  signal(SIGINT, SIG_DFL); // reset signal handler - bit extra safety
39  Modes.exit = 1; // Signal to threads that we are done
40 }
41 //
42 // =============================== Initialization ===========================
43 //
44 void modesInitConfig(void) {
45  // Default everything to zero/NULL
46  memset(&Modes, 0, sizeof(Modes));
47 
48  // Now initialise things that should not be 0/NULL to their defaults
49  Modes.gain = MODES_MAX_GAIN;
51  Modes.check_crc = 1;
52  Modes.net_output_sbs_port = MODES_NET_OUTPUT_SBS_PORT;
53  Modes.net_output_raw_port = MODES_NET_OUTPUT_RAW_PORT;
54  Modes.net_input_raw_port = MODES_NET_INPUT_RAW_PORT;
55  Modes.net_output_beast_port = MODES_NET_OUTPUT_BEAST_PORT;
56  Modes.net_input_beast_port = MODES_NET_INPUT_BEAST_PORT;
57  Modes.net_http_port = MODES_NET_HTTP_PORT;
58  Modes.interactive_rows = MODES_INTERACTIVE_ROWS;
59  Modes.interactive_delete_ttl = MODES_INTERACTIVE_DELETE_TTL;
60  Modes.interactive_display_ttl = MODES_INTERACTIVE_DISPLAY_TTL;
63 }
64 //
65 //=========================================================================
66 //
67 void modesInit(void) {
68  int i, q;
69 
70  pthread_mutex_init(&Modes.data_mutex,NULL);
71  pthread_cond_init(&Modes.data_cond,NULL);
72 
73  // Allocate the various buffers used by Modes
74  if ( ((Modes.icao_cache = (uint32_t *) malloc(sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2) ) == NULL) ||
75  ((Modes.data = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE) ) == NULL) ||
76  ((Modes.magnitude = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE+MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE) ) == NULL) ||
77  ((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
78  ((Modes.beastOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) ||
79  ((Modes.rawOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) )
80  {
81  fprintf(stderr, "Out of memory allocating data buffer.\n");
82  exit(1);
83  }
84 
85  // Clear the buffers that have just been allocated, just in-case
86  memset(Modes.icao_cache, 0, sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);
87  memset(Modes.data, 127, MODES_ASYNC_BUF_SIZE);
89 
90  // Validate the users Lat/Lon home location inputs
91  if ( (Modes.fUserLat > 90.0) // Latitude must be -90 to +90
92  || (Modes.fUserLat < -90.0) // and
93  || (Modes.fUserLon > 360.0) // Longitude must be -180 to +360
94  || (Modes.fUserLon < -180.0) ) {
95  Modes.fUserLat = Modes.fUserLon = 0.0;
96  } else if (Modes.fUserLon > 180.0) { // If Longitude is +180 to +360, make it -180 to 0
97  Modes.fUserLon -= 360.0;
98  }
99  // If both Lat and Lon are 0.0 then the users location is either invalid/not-set, or (s)he's in the
100  // Atlantic ocean off the west coast of Africa. This is unlikely to be correct.
101  // Set the user LatLon valid flag only if either Lat or Lon are non zero. Note the Greenwich meridian
102  // is at 0.0 Lon,so we must check for either fLat or fLon being non zero not both.
103  // Testing the flag at runtime will be much quicker than ((fLon != 0.0) || (fLat != 0.0))
104  Modes.bUserFlags &= ~MODES_USER_LATLON_VALID;
105  if ((Modes.fUserLat != 0.0) || (Modes.fUserLon != 0.0)) {
106  Modes.bUserFlags |= MODES_USER_LATLON_VALID;
107  }
108 
109  // Limit the maximum requested raw output size to less than one Ethernet Block
110  if (Modes.net_output_raw_size > (MODES_RAWOUT_BUF_FLUSH))
111  {Modes.net_output_raw_size = MODES_RAWOUT_BUF_FLUSH;}
112  if (Modes.net_output_raw_rate > (MODES_RAWOUT_BUF_RATE))
113  {Modes.net_output_raw_rate = MODES_RAWOUT_BUF_RATE;}
114 
115  // Initialise the Block Timers to something half sensible
116  ftime(&Modes.stSystemTimeRTL);
117  Modes.stSystemTimeBlk = Modes.stSystemTimeRTL;
118 
119  // Each I and Q value varies from 0 to 255, which represents a range from -1 to +1. To get from the
120  // unsigned (0-255) range you therefore subtract 127 (or 128 or 127.5) from each I and Q, giving you
121  // a range from -127 to +128 (or -128 to +127, or -127.5 to +127.5)..
122  //
123  // To decode the AM signal, you need the magnitude of the waveform, which is given by sqrt((I^2)+(Q^2))
124  // The most this could be is if I&Q are both 128 (or 127 or 127.5), so you could end up with a magnitude
125  // of 181.019 (or 179.605, or 180.312)
126  //
127  // However, in reality the magnitude of the signal should never exceed the range -1 to +1, because the
128  // values are I = rCos(w) and Q = rSin(w). Therefore the integer computed magnitude should (can?) never
129  // exceed 128 (or 127, or 127.5 or whatever)
130  //
131  // If we scale up the results so that they range from 0 to 65535 (16 bits) then we need to multiply
132  // by 511.99, (or 516.02 or 514). antirez's original code multiplies by 360, presumably because he's
133  // assuming the maximim calculated amplitude is 181.019, and (181.019 * 360) = 65166.
134  //
135  // So lets see if we can improve things by subtracting 127.5, Well in integer arithmatic we can't
136  // subtract half, so, we'll double everything up and subtract one, and then compensate for the doubling
137  // in the multiplier at the end.
138  //
139  // If we do this we can never have I or Q equal to 0 - they can only be as small as +/- 1.
140  // This gives us a minimum magnitude of root 2 (0.707), so the dynamic range becomes (1.414-255). This
141  // also affects our scaling value, which is now 65535/(255 - 1.414), or 258.433254
142  //
143  // The sums then become mag = 258.433254 * (sqrt((I*2-255)^2 + (Q*2-255)^2) - 1.414)
144  // or mag = (258.433254 * sqrt((I*2-255)^2 + (Q*2-255)^2)) - 365.4798
145  //
146  // We also need to clip mag just incaes any rogue I/Q values somehow do have a magnitude greater than 255.
147  //
148 
149  for (i = 0; i <= 255; i++) {
150  for (q = 0; q <= 255; q++) {
151  int mag, mag_i, mag_q;
152 
153  mag_i = (i * 2) - 255;
154  mag_q = (q * 2) - 255;
155 
156  mag = (int) round((sqrt((mag_i*mag_i)+(mag_q*mag_q)) * 258.433254) - 365.4798);
157 
158  Modes.maglut[(i*256)+q] = (uint16_t) ((mag < 65535) ? mag : 65535);
159  }
160  }
161 
162  // Prepare error correction tables
164 }
165 //
166 // =============================== RTLSDR handling ==========================
167 //
168 void modesInitRTLSDR(void) {
169  int j;
170  int device_count;
171  char vendor[256], product[256], serial[256];
172 
173  device_count = rtlsdr_get_device_count();
174  if (!device_count) {
175  fprintf(stderr, "No supported RTLSDR devices found.\n");
176  exit(1);
177  }
178 
179  fprintf(stderr, "Found %d device(s):\n", device_count);
180  for (j = 0; j < device_count; j++) {
181  rtlsdr_get_device_usb_strings(j, vendor, product, serial);
182  fprintf(stderr, "%d: %s, %s, SN: %s %s\n", j, vendor, product, serial,
183  (j == Modes.dev_index) ? "(currently selected)" : "");
184  }
185 
186  if (rtlsdr_open(&Modes.dev, Modes.dev_index) < 0) {
187  fprintf(stderr, "Error opening the RTLSDR device: %s\n",
188  strerror(errno));
189  exit(1);
190  }
191 
192  // Set gain, frequency, sample rate, and reset the device
193  rtlsdr_set_tuner_gain_mode(Modes.dev,
194  (Modes.gain == MODES_AUTO_GAIN) ? 0 : 1);
195  if (Modes.gain != MODES_AUTO_GAIN) {
196  if (Modes.gain == MODES_MAX_GAIN) {
197  // Find the maximum gain available
198  int numgains;
199  int gains[100];
200 
201  numgains = rtlsdr_get_tuner_gains(Modes.dev, gains);
202  Modes.gain = gains[numgains-1];
203  fprintf(stderr, "Max available gain is: %.2f\n", Modes.gain/10.0);
204  }
205  rtlsdr_set_tuner_gain(Modes.dev, Modes.gain);
206  fprintf(stderr, "Setting gain to: %.2f\n", Modes.gain/10.0);
207  } else {
208  fprintf(stderr, "Using automatic gain control.\n");
209  }
210  rtlsdr_set_freq_correction(Modes.dev, Modes.ppm_error);
211  if (Modes.enable_agc) rtlsdr_set_agc_mode(Modes.dev, 1);
212  rtlsdr_set_center_freq(Modes.dev, Modes.freq);
213  rtlsdr_set_sample_rate(Modes.dev, MODES_DEFAULT_RATE);
214  rtlsdr_reset_buffer(Modes.dev);
215  fprintf(stderr, "Gain reported by device: %.2f\n",
216  rtlsdr_get_tuner_gain(Modes.dev)/10.0);
217 }
218 //
219 //=========================================================================
220 //
221 // We use a thread reading data in background, while the main thread
222 // handles decoding and visualization of data to the user.
223 //
224 // The reading thread calls the RTLSDR API to read data asynchronously, and
225 // uses a callback to populate the data buffer.
226 //
227 // A Mutex is used to avoid races with the decoding thread.
228 //
229 void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) {
230 
231  MODES_NOTUSED(ctx);
232 
233  pthread_mutex_lock(&Modes.data_mutex);
234  ftime(&Modes.stSystemTimeRTL);
236  // Read the new data
237  memcpy(Modes.data, buf, len);
238  Modes.data_ready = 1;
239  // Signal to the other thread that new data is ready
240  pthread_cond_signal(&Modes.data_cond);
241  pthread_mutex_unlock(&Modes.data_mutex);
242 }
243 //
244 //=========================================================================
245 //
246 // This is used when --ifile is specified in order to read data from file
247 // instead of using an RTLSDR device
248 //
249 void readDataFromFile(void) {
250  pthread_mutex_lock(&Modes.data_mutex);
251  while(1) {
252  ssize_t nread, toread;
253  unsigned char *p;
254 
255  if (Modes.exit == 1) break;
256  if (Modes.data_ready) {
257  pthread_cond_wait(&Modes.data_cond,&Modes.data_mutex);
258  continue;
259  }
260 
261  if (Modes.interactive) {
262  // When --ifile and --interactive are used together, slow down
263  // playing at the natural rate of the RTLSDR received.
264  pthread_mutex_unlock(&Modes.data_mutex);
265  usleep(64000);
266  pthread_mutex_lock(&Modes.data_mutex);
267  }
268 
269  toread = MODES_ASYNC_BUF_SIZE;
270  p = (unsigned char *) Modes.data;
271  while(toread) {
272  nread = read(Modes.fd, p, toread);
273  if (nread <= 0) {
274  Modes.exit = 1; // Signal the other threads to exit.
275  break;
276  }
277  p += nread;
278  toread -= nread;
279  }
280  if (toread) {
281  // Not enough data on file to fill the buffer? Pad with no signal.
282  memset(p,127,toread);
283  }
284  Modes.data_ready = 1;
285  // Signal to the other thread that new data is ready
286  pthread_cond_signal(&Modes.data_cond);
287  }
288 }
289 //
290 //=========================================================================
291 //
292 // We read data using a thread, so the main thread only handles decoding
293 // without caring about data acquisition
294 //
295 void *readerThreadEntryPoint(void *arg) {
296  MODES_NOTUSED(arg);
297 
298  if (Modes.filename == NULL) {
299  rtlsdr_read_async(Modes.dev, rtlsdrCallback, NULL,
302  } else {
304  }
305  // Signal to the other thread that new data is ready - dummy really so threads don't mutually lock
306  Modes.data_ready = 1;
307  pthread_cond_signal(&Modes.data_cond);
308  pthread_mutex_unlock(&Modes.data_mutex);
309 #ifndef _WIN32
310  pthread_exit(NULL);
311 #else
312  return NULL;
313 #endif
314 }
315 //
316 // ============================== Snip mode =================================
317 //
318 // Get raw IQ samples and filter everything is < than the specified level
319 // for more than 256 samples in order to reduce example file size
320 //
321 void snipMode(int level) {
322  int i, q;
323  uint64_t c = 0;
324 
325  while ((i = getchar()) != EOF && (q = getchar()) != EOF) {
326  if (abs(i-127) < level && abs(q-127) < level) {
327  c++;
328  if (c > MODES_PREAMBLE_SIZE) continue;
329  } else {
330  c = 0;
331  }
332  putchar(i);
333  putchar(q);
334  }
335 }
336 //
337 // ================================ Main ====================================
338 //
339 void showHelp(void) {
340  printf(
341 "-----------------------------------------------------------------------------\n"
342 "| dump1090 ModeS Receiver Ver : " MODES_DUMP1090_VERSION " |\n"
343 "-----------------------------------------------------------------------------\n"
344 "--device-index <index> Select RTL device (default: 0)\n"
345 "--gain <db> Set gain (default: max gain. Use -100 for auto-gain)\n"
346 "--enable-agc Enable the Automatic Gain Control (default: off)\n"
347 "--freq <hz> Set frequency (default: 1090 Mhz)\n"
348 "--ifile <filename> Read data from file (use '-' for stdin)\n"
349 "--interactive Interactive mode refreshing data on screen\n"
350 "--interactive-rows <num> Max number of rows in interactive mode (default: 15)\n"
351 "--interactive-ttl <sec> Remove from list if idle for <sec> (default: 60)\n"
352 "--interactive-rtl1090 Display flight table in RTL1090 format\n"
353 "--raw Show only messages hex values\n"
354 "--raw-with-timestamp Show messages hex values prepended with a timestamp.\n"
355 "--aera Save received airplane position to logfile\n"
356 "--aera-net <hostname> <port> Save received aiplane position to logfile and send to socket\n"
357 "--net Enable networking\n"
358 "--modeac Enable decoding of SSR Modes 3/A & 3/C\n"
359 "--net-beast TCP raw output in Beast binary format\n"
360 "--net-only Enable just networking, no RTL device or file used\n"
361 "--net-http-port <port> HTTP server port (default: 8080)\n"
362 "--net-ri-port <port> TCP raw input listen port (default: 30001)\n"
363 "--net-ro-port <port> TCP raw output listen port (default: 30002)\n"
364 "--net-sbs-port <port> TCP BaseStation output listen port (default: 30003)\n"
365 "--net-bi-port <port> TCP Beast input listen port (default: 30004)\n"
366 "--net-bo-port <port> TCP Beast output listen port (default: 30005)\n"
367 "--net-ro-size <size> TCP raw output minimum size (default: 0)\n"
368 "--net-ro-rate <rate> TCP raw output memory flush rate (default: 0)\n"
369 "--lat <latitude> Reference/receiver latitide for surface posn (opt)\n"
370 "--lon <longitude> Reference/receiver longitude for surface posn (opt)\n"
371 "--fix Enable single-bits error correction using CRC\n"
372 "--no-fix Disable single-bits error correction using CRC\n"
373 "--no-crc-check Disable messages with broken CRC (discouraged)\n"
374 "--phase-enhance Enable phase enhancement\n"
375 "--aggressive More CPU for more messages (two bits fixes, ...)\n"
376 "--mlat display raw messages in Beast ascii mode\n"
377 "--stats With --ifile print stats at exit. No other output\n"
378 "--onlyaddr Show only ICAO addresses (testing purposes)\n"
379 "--metric Use metric units (meters, km/h, ...)\n"
380 "--snip <level> Strip IQ file removing samples < level\n"
381 "--debug <flags> Debug mode (verbose), see README for details\n"
382 "--quiet Disable output to stdout. Use for daemon applications\n"
383 "--ppm <error> Set receiver error in parts per million (default 0)\n"
384 "--help Show this help\n"
385 "\n"
386 "Debug mode flags: d = Log frames decoded with errors\n"
387 " D = Log frames decoded with zero errors\n"
388 " c = Log frames with bad CRC\n"
389 " C = Log frames with good CRC\n"
390 " p = Log frames with bad preamble\n"
391 " n = Log network debugging info\n"
392 " j = Log frames to frames.js, loadable by debug.html\n"
393  );
394 }
395 //
396 //=========================================================================
397 //
398 // This function is called a few times every second by main in order to
399 // perform tasks we need to do continuously, like accepting new clients
400 // from the net, refreshing the screen in interactive mode, and so forth
401 //
402 void backgroundTasks(void) {
403  if (Modes.net) {
405  }
406 
407  // If Modes.aircrafts is not NULL, remove any stale aircraft
408  if (Modes.aircrafts) {
410  }
411 
412  // Refresh screen when in interactive mode
413  if (Modes.interactive) {
415  }
416 }
417 //
418 //=========================================================================
419 //
420 int main(int argc, char **argv) {
421  int j;
422 
423  // Set sane defaults
424  modesInitConfig();
425  signal(SIGINT, sigintHandler); // Define Ctrl/C handler (exit program)
426 
427  // Parse the command line options
428  for (j = 1; j < argc; j++) {
429  int more = j+1 < argc; // There are more arguments
430 
431  if (!strcmp(argv[j],"--device-index") && more) {
432  Modes.dev_index = atoi(argv[++j]);
433  } else if (!strcmp(argv[j],"--gain") && more) {
434  Modes.gain = (int) atof(argv[++j])*10; // Gain is in tens of DBs
435  } else if (!strcmp(argv[j],"--enable-agc")) {
436  Modes.enable_agc++;
437  } else if (!strcmp(argv[j],"--freq") && more) {
438  Modes.freq = (int) strtoll(argv[++j],NULL,10);
439  } else if (!strcmp(argv[j],"--ifile") && more) {
440  Modes.filename = strdup(argv[++j]);
441  } else if (!strcmp(argv[j],"--fix")) {
442  Modes.nfix_crc = 1;
443  } else if (!strcmp(argv[j],"--no-fix")) {
444  Modes.nfix_crc = 0;
445  } else if (!strcmp(argv[j],"--no-crc-check")) {
446  Modes.check_crc = 0;
447  } else if (!strcmp(argv[j],"--phase-enhance")) {
448  Modes.phase_enhance = 1;
449  } else if (!strcmp(argv[j],"--raw")) {
450  Modes.raw = 1;
451  } else if (!strcmp(argv[j],"--raw-with-timestamp")) {
452  Modes.raw = 1;
453  Modes.print_timestamp = 1;
454  } else if (!strcmp(argv[j],"--aera")) {
455  Modes.aera = 1; // second is port number
456  } else if (!strcmp(argv[j],"--aera-net") && (j+2 < argc)) {
457  Modes.aera_net = strdup(argv[++j]); // first argument is hostname
458  Modes.aera = atoi(argv[++j]); // second is port number
459  if (Modes.aera < 1 || Modes.aera > 65535) { // check if port is valid (between 1 and 65535)
460  fprintf(stderr,
461  "Unknown port number for option '--aera'.\nusage --aera <hostname> <port>\n\n\n");
462  showHelp();
463  exit(1);
464  }
465  } else if (!strcmp(argv[j],"--net")) {
466  Modes.net = 1;
467  } else if (!strcmp(argv[j],"--modeac")) {
468  Modes.mode_ac = 1;
469  } else if (!strcmp(argv[j],"--net-beast")) {
470  Modes.beast = 1;
471  } else if (!strcmp(argv[j],"--net-only")) {
472  Modes.net = 1;
473  Modes.net_only = 1;
474  } else if (!strcmp(argv[j],"--net-ro-size") && more) {
475  Modes.net_output_raw_size = atoi(argv[++j]);
476  } else if (!strcmp(argv[j],"--net-ro-rate") && more) {
477  Modes.net_output_raw_rate = atoi(argv[++j]);
478  } else if (!strcmp(argv[j],"--net-ro-port") && more) {
479  if (Modes.beast) // Required for legacy backward compatibility
480  {Modes.net_output_beast_port = atoi(argv[++j]);;}
481  else
482  {Modes.net_output_raw_port = atoi(argv[++j]);}
483  } else if (!strcmp(argv[j],"--net-ri-port") && more) {
484  Modes.net_input_raw_port = atoi(argv[++j]);
485  } else if (!strcmp(argv[j],"--net-bo-port") && more) {
486  Modes.net_output_beast_port = atoi(argv[++j]);
487  } else if (!strcmp(argv[j],"--net-bi-port") && more) {
488  Modes.net_input_beast_port = atoi(argv[++j]);
489  } else if (!strcmp(argv[j],"--net-http-port") && more) {
490  Modes.net_http_port = atoi(argv[++j]);
491  } else if (!strcmp(argv[j],"--net-sbs-port") && more) {
492  Modes.net_output_sbs_port = atoi(argv[++j]);
493  } else if (!strcmp(argv[j],"--onlyaddr")) {
494  Modes.onlyaddr = 1;
495  } else if (!strcmp(argv[j],"--metric")) {
496  Modes.metric = 1;
497  } else if (!strcmp(argv[j],"--aggressive")) {
498  Modes.nfix_crc = MODES_MAX_BITERRORS;
499  } else if (!strcmp(argv[j],"--interactive")) {
500  Modes.interactive = 1;
501  } else if (!strcmp(argv[j],"--interactive-rows") && more) {
502  Modes.interactive_rows = atoi(argv[++j]);
503  } else if (!strcmp(argv[j],"--interactive-ttl") && more) {
504  Modes.interactive_display_ttl = atoi(argv[++j]);
505  } else if (!strcmp(argv[j],"--lat") && more) {
506  Modes.fUserLat = atof(argv[++j]);
507  } else if (!strcmp(argv[j],"--lon") && more) {
508  Modes.fUserLon = atof(argv[++j]);
509  } else if (!strcmp(argv[j],"--debug") && more) {
510  char *f = argv[++j];
511  while(*f) {
512  switch(*f) {
513  case 'D': Modes.debug |= MODES_DEBUG_DEMOD; break;
514  case 'd': Modes.debug |= MODES_DEBUG_DEMODERR; break;
515  case 'C': Modes.debug |= MODES_DEBUG_GOODCRC; break;
516  case 'c': Modes.debug |= MODES_DEBUG_BADCRC; break;
517  case 'p': Modes.debug |= MODES_DEBUG_NOPREAMBLE; break;
518  case 'n': Modes.debug |= MODES_DEBUG_NET; break;
519  case 'j': Modes.debug |= MODES_DEBUG_JS; break;
520  default:
521  fprintf(stderr, "Unknown debugging flag: %c\n", *f);
522  exit(1);
523  break;
524  }
525  f++;
526  }
527  } else if (!strcmp(argv[j],"--stats")) {
528  Modes.stats = 1;
529  } else if (!strcmp(argv[j],"--snip") && more) {
530  snipMode(atoi(argv[++j]));
531  exit(0);
532  } else if (!strcmp(argv[j],"--help")) {
533  showHelp();
534  exit(0);
535  } else if (!strcmp(argv[j],"--ppm") && more) {
536  Modes.ppm_error = atoi(argv[++j]);
537  } else if (!strcmp(argv[j],"--quiet")) {
538  Modes.quiet = 1;
539  } else if (!strcmp(argv[j],"--mlat")) {
540  Modes.mlat = 1;
541  } else if (!strcmp(argv[j],"--interactive-rtl1090")) {
542  Modes.interactive = 1;
543  Modes.interactive_rtl1090 = 1;
544  } else {
545  fprintf(stderr,
546  "Unknown or not enough arguments for option '%s'.\n\n",
547  argv[j]);
548  showHelp();
549  exit(1);
550  }
551  }
552 
553  // Initialization
554  modesInit();
555 
556  //if (Modes.debug & MODES_DEBUG_BADCRC) {
557  // testAndTimeBitCorrection();
558  //}
559 
560  if (Modes.net_only) {
561  fprintf(stderr,"Net-only mode, no RTL device or file open.\n");
562  } else if (Modes.filename == NULL) {
563  modesInitRTLSDR();
564  } else {
565  if (Modes.filename[0] == '-' && Modes.filename[1] == '\0') {
566  Modes.fd = STDIN_FILENO;
567  } else if ((Modes.fd = open(Modes.filename,O_RDONLY)) == -1) {
568  perror("Opening data file");
569  exit(1);
570  }
571  }
572  if (Modes.net) modesInitNet();
573  if (Modes.aera_net) { // connect to AERA T3Maker Socket
575  aeraConnectToSocket(aeraSocketFD, Modes.aera_net, Modes.aera);
576  }
577 
578  // If the user specifies --net-only, just run in order to serve network
579  // clients without reading data from the RTL device
580  while (Modes.net_only) {
581  if (Modes.exit) exit(0); // If we exit net_only nothing further in main()
582  backgroundTasks();
583  usleep(100000);
584  }
585 
586  // Create the thread that will read the data from the device.
587  pthread_create(&Modes.reader_thread, NULL, readerThreadEntryPoint, NULL);
588 
589  pthread_mutex_lock(&Modes.data_mutex);
590  while(1) {
591  if (!Modes.data_ready) {
592  pthread_cond_wait(&Modes.data_cond,&Modes.data_mutex);
593  continue;
594  }
596  Modes.stSystemTimeBlk = Modes.stSystemTimeRTL;
597 
598  // Signal to the other thread that we processed the available data
599  // and we want more (useful for --ifile)
600  Modes.data_ready = 0;
601  pthread_cond_signal(&Modes.data_cond);
602 
603  // Process data after releasing the lock, so that the capturing
604  // thread can read data while we perform computationally expensive
605  // stuff * at the same time. (This should only be useful with very
606  // slow processors).
607  pthread_mutex_unlock(&Modes.data_mutex);
609  Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES*6);
610  backgroundTasks();
611  pthread_mutex_lock(&Modes.data_mutex);
612  if (Modes.exit) break;
613  }
614 
615  // If --stats were given, print statistics
616  if (Modes.stats) {
617  printf("\n\n");
618  if (Modes.interactive)
620  printf("%d ModeA/C detected\n", Modes.stat_ModeAC);
621  printf("%d valid Mode-S preambles\n", Modes.stat_valid_preamble);
622  printf("%d DF-?? fields corrected for length\n", Modes.stat_DF_Len_Corrected);
623  printf("%d DF-?? fields corrected for type\n", Modes.stat_DF_Type_Corrected);
624  printf("%d demodulated with 0 errors\n", Modes.stat_demodulated0);
625  printf("%d demodulated with 1 error\n", Modes.stat_demodulated1);
626  printf("%d demodulated with 2 errors\n", Modes.stat_demodulated2);
627  printf("%d demodulated with > 2 errors\n", Modes.stat_demodulated3);
628  printf("%d with good crc\n", Modes.stat_goodcrc);
629  printf("%d with bad crc\n", Modes.stat_badcrc);
630  printf("%d errors corrected\n", Modes.stat_fixed);
631  for (j = 0; j < MODES_MAX_BITERRORS; j++) {
632  printf(" %d with %d bit %s\n", Modes.stat_bit_fix[j], j+1, (j==0)?"error":"errors");
633  }
634  if (Modes.phase_enhance) {
635  printf("%d phase enhancement attempts\n", Modes.stat_out_of_phase);
636  printf("%d phase enhanced demodulated with 0 errors\n", Modes.stat_ph_demodulated0);
637  printf("%d phase enhanced demodulated with 1 error\n", Modes.stat_ph_demodulated1);
638  printf("%d phase enhanced demodulated with 2 errors\n", Modes.stat_ph_demodulated2);
639  printf("%d phase enhanced demodulated with > 2 errors\n", Modes.stat_ph_demodulated3);
640  printf("%d phase enhanced with good crc\n", Modes.stat_ph_goodcrc);
641  printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc);
642  printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed);
643  for (j = 0; j < MODES_MAX_BITERRORS; j++) {
644  printf(" %d with %d bit %s\n", Modes.stat_ph_bit_fix[j], j+1, (j==0)?"error":"errors");
645  }
646  }
647  printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed);
648  }
649 
650  if (Modes.filename == NULL) {
651  rtlsdr_cancel_async(Modes.dev); // Cancel rtlsdr_read_async will cause data input thread to terminate cleanly
652  rtlsdr_close(Modes.dev);
653  }
654  pthread_cond_destroy(&Modes.data_cond); // Thread cleanup
655  pthread_mutex_destroy(&Modes.data_mutex);
656  pthread_join(Modes.reader_thread,NULL); // Wait on reader thread exit
657  pthread_exit(0);
658 }
659 //
660 //=========================================================================
661 //
void interactiveRemoveStaleAircrafts(void)
Definition: interactive.c:446
#define MODES_DEBUG_NET
Definition: dump1090.h:153
void showHelp(void)
Definition: dump1090.c:339
void detectModeS(uint16_t *m, uint32_t mlen)
Definition: mode_s.c:1466
int * aeraSocketFD
Definition: aera.h:41
void sigintHandler(int dummy)
Definition: dump1090.c:36
void interactiveShowData(void)
Definition: interactive.c:324
int aeraSocketFD2
Definition: aera.h:41
void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx)
Definition: dump1090.c:229
#define MODES_ICAO_CACHE_LEN
Definition: dump1090.h:120
#define MODES_DEBUG_GOODCRC
Definition: dump1090.h:151
#define MODES_DEFAULT_FREQ
Definition: dump1090.h:80
#define MODES_ASYNC_BUF_NUMBER
Definition: dump1090.h:83
#define MODES_NET_OUTPUT_SBS_PORT
Definition: dump1090.h:168
#define MODES_PREAMBLE_SIZE
Definition: dump1090.h:106
void snipMode(int level)
Definition: dump1090.c:321
int exit
Definition: dump1090.h:237
#define MODES_USER_LATITUDE_DFLT
Definition: dump1090.h:75
void modesInitErrorInfo()
Definition: mode_s.c:234
#define MODES_DEBUG_JS
Definition: dump1090.h:154
#define MODES_ASYNC_BUF_SIZE
Definition: dump1090.h:84
#define MODES_RAWOUT_BUF_SIZE
Definition: dump1090.h:116
void * readerThreadEntryPoint(void *arg)
Definition: dump1090.c:295
#define MODES_USER_LONGITUDE_DFLT
Definition: dump1090.h:76
#define MODES_AUTO_GAIN
Definition: dump1090.h:86
#define MODES_INTERACTIVE_DISPLAY_TTL
Definition: dump1090.h:163
#define MODES_NET_INPUT_RAW_PORT
Definition: dump1090.h:166
int main(int argc, char *argv[])
Definition: DBSync.cc:58
void modesReadFromClients(void)
Definition: net_io.c:860
void backgroundTasks(void)
Definition: dump1090.c:402
struct @0 Modes
double abs(const SVector< n, T > &v)
#define MODES_DEFAULT_RATE
Definition: dump1090.h:79
#define MODES_RAWOUT_BUF_RATE
Definition: dump1090.h:118
#define MODES_MAX_GAIN
Definition: dump1090.h:87
void modesInit(void)
Definition: dump1090.c:67
#define MODES_NET_INPUT_BEAST_PORT
Definition: dump1090.h:169
#define MODES_MAX_BITERRORS
Definition: dump1090.h:92
void modesInitNet(void)
Definition: net_io.c:49
#define MODES_INTERACTIVE_DELETE_TTL
Definition: dump1090.h:162
#define MODES_DEBUG_DEMOD
Definition: dump1090.h:148
#define MODES_DEBUG_DEMODERR
Definition: dump1090.h:149
#define MODES_NET_OUTPUT_RAW_PORT
Definition: dump1090.h:167
#define MODES_DEBUG_NOPREAMBLE
Definition: dump1090.h:152
#define MODES_ASYNC_BUF_SAMPLES
Definition: dump1090.h:85
#define MODES_DUMP1090_VERSION
Definition: dump1090.h:40
void modesInitConfig(void)
Definition: dump1090.c:44
void computeMagnitudeVector()
Definition: mode_s.c:1386
#define MODES_RAWOUT_BUF_FLUSH
Definition: dump1090.h:117
#define MODES_USER_LATLON_VALID
Definition: dump1090.h:125
#define MODES_LONG_MSG_SIZE
Definition: dump1090.h:113
#define MODES_DEBUG_BADCRC
Definition: dump1090.h:150
#define MODES_NET_OUTPUT_BEAST_PORT
Definition: dump1090.h:170
#define MODES_NET_HTTP_PORT
Definition: dump1090.h:171
#define MODES_NOTUSED(V)
Definition: dump1090.h:179
void modesInitRTLSDR(void)
Definition: dump1090.c:168
int aeraConnectToSocket(int *aeraSocketFD, char host[], int port)
Definition: aera.c:236
#define MODES_INTERACTIVE_ROWS
Definition: dump1090.h:161
void readDataFromFile(void)
Definition: dump1090.c:249

, generated on Tue Sep 26 2023.