38 signal(SIGINT, SIG_DFL);
70 pthread_mutex_init(&
Modes.data_mutex,NULL);
71 pthread_cond_init(&
Modes.data_cond,NULL);
77 ((
Modes.maglut = (uint16_t *) malloc(
sizeof(uint16_t) * 256 * 256) ) == NULL) ||
81 fprintf(stderr,
"Out of memory allocating data buffer.\n");
86 memset(
Modes.icao_cache, 0,
sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);
91 if ( (
Modes.fUserLat > 90.0)
92 || (
Modes.fUserLat < -90.0)
93 || (
Modes.fUserLon > 360.0)
94 || (
Modes.fUserLon < -180.0) ) {
96 }
else if (
Modes.fUserLon > 180.0) {
97 Modes.fUserLon -= 360.0;
105 if ((
Modes.fUserLat != 0.0) || (
Modes.fUserLon != 0.0)) {
116 ftime(&
Modes.stSystemTimeRTL);
117 Modes.stSystemTimeBlk =
Modes.stSystemTimeRTL;
149 for (i = 0; i <= 255; i++) {
150 for (q = 0; q <= 255; q++) {
151 int mag, mag_i, mag_q;
153 mag_i = (i * 2) - 255;
154 mag_q = (q * 2) - 255;
156 mag = (int) round((
sqrt((mag_i*mag_i)+(mag_q*mag_q)) * 258.433254) - 365.4798);
158 Modes.maglut[(i*256)+q] = (uint16_t) ((mag < 65535) ? mag : 65535);
171 char vendor[256], product[256], serial[256];
173 device_count = rtlsdr_get_device_count();
175 fprintf(stderr,
"No supported RTLSDR devices found.\n");
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)" :
"");
186 if (rtlsdr_open(&
Modes.dev,
Modes.dev_index) < 0) {
187 fprintf(stderr,
"Error opening the RTLSDR device: %s\n",
193 rtlsdr_set_tuner_gain_mode(
Modes.dev,
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);
206 fprintf(stderr,
"Setting gain to: %.2f\n",
Modes.gain/10.0);
208 fprintf(stderr,
"Using automatic gain control.\n");
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);
214 rtlsdr_reset_buffer(
Modes.dev);
215 fprintf(stderr,
"Gain reported by device: %.2f\n",
216 rtlsdr_get_tuner_gain(
Modes.dev)/10.0);
233 pthread_mutex_lock(&
Modes.data_mutex);
234 ftime(&
Modes.stSystemTimeRTL);
237 memcpy(
Modes.data, buf, len);
238 Modes.data_ready = 1;
240 pthread_cond_signal(&
Modes.data_cond);
241 pthread_mutex_unlock(&
Modes.data_mutex);
250 pthread_mutex_lock(&
Modes.data_mutex);
252 ssize_t nread, toread;
255 if (
Modes.exit == 1)
break;
256 if (
Modes.data_ready) {
257 pthread_cond_wait(&
Modes.data_cond,&
Modes.data_mutex);
261 if (
Modes.interactive) {
264 pthread_mutex_unlock(&
Modes.data_mutex);
266 pthread_mutex_lock(&
Modes.data_mutex);
270 p = (
unsigned char *)
Modes.data;
272 nread = read(
Modes.fd, p, toread);
282 memset(p,127,toread);
284 Modes.data_ready = 1;
286 pthread_cond_signal(&
Modes.data_cond);
298 if (
Modes.filename == NULL) {
306 Modes.data_ready = 1;
307 pthread_cond_signal(&
Modes.data_cond);
308 pthread_mutex_unlock(&
Modes.data_mutex);
325 while ((i = getchar()) != EOF && (q = getchar()) != EOF) {
326 if (
abs(i-127) < level &&
abs(q-127) < level) {
341 "-----------------------------------------------------------------------------\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"
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"
408 if (
Modes.aircrafts) {
413 if (
Modes.interactive) {
420 int main(
int argc,
char **argv) {
428 for (j = 1; j < argc; j++) {
429 int more = j+1 < argc;
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;
435 }
else if (!strcmp(argv[j],
"--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")) {
443 }
else if (!strcmp(argv[j],
"--no-fix")) {
445 }
else if (!strcmp(argv[j],
"--no-crc-check")) {
447 }
else if (!strcmp(argv[j],
"--phase-enhance")) {
448 Modes.phase_enhance = 1;
449 }
else if (!strcmp(argv[j],
"--raw")) {
451 }
else if (!strcmp(argv[j],
"--raw-with-timestamp")) {
453 Modes.print_timestamp = 1;
454 }
else if (!strcmp(argv[j],
"--aera")) {
456 }
else if (!strcmp(argv[j],
"--aera-net") && (j+2 < argc)) {
457 Modes.aera_net = strdup(argv[++j]);
458 Modes.aera = atoi(argv[++j]);
461 "Unknown port number for option '--aera'.\nusage --aera <hostname> <port>\n\n\n");
465 }
else if (!strcmp(argv[j],
"--net")) {
467 }
else if (!strcmp(argv[j],
"--modeac")) {
469 }
else if (!strcmp(argv[j],
"--net-beast")) {
471 }
else if (!strcmp(argv[j],
"--net-only")) {
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) {
480 {
Modes.net_output_beast_port = atoi(argv[++j]);;}
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")) {
495 }
else if (!strcmp(argv[j],
"--metric")) {
497 }
else if (!strcmp(argv[j],
"--aggressive")) {
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) {
521 fprintf(stderr,
"Unknown debugging flag: %c\n", *f);
527 }
else if (!strcmp(argv[j],
"--stats")) {
529 }
else if (!strcmp(argv[j],
"--snip") && more) {
532 }
else if (!strcmp(argv[j],
"--help")) {
535 }
else if (!strcmp(argv[j],
"--ppm") && more) {
536 Modes.ppm_error = atoi(argv[++j]);
537 }
else if (!strcmp(argv[j],
"--quiet")) {
539 }
else if (!strcmp(argv[j],
"--mlat")) {
541 }
else if (!strcmp(argv[j],
"--interactive-rtl1090")) {
542 Modes.interactive = 1;
543 Modes.interactive_rtl1090 = 1;
546 "Unknown or not enough arguments for option '%s'.\n\n",
560 if (
Modes.net_only) {
561 fprintf(stderr,
"Net-only mode, no RTL device or file open.\n");
562 }
else if (
Modes.filename == NULL) {
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");
573 if (
Modes.aera_net) {
580 while (
Modes.net_only) {
589 pthread_mutex_lock(&
Modes.data_mutex);
591 if (!
Modes.data_ready) {
592 pthread_cond_wait(&
Modes.data_cond,&
Modes.data_mutex);
596 Modes.stSystemTimeBlk =
Modes.stSystemTimeRTL;
600 Modes.data_ready = 0;
601 pthread_cond_signal(&
Modes.data_cond);
607 pthread_mutex_unlock(&
Modes.data_mutex);
611 pthread_mutex_lock(&
Modes.data_mutex);
612 if (
Modes.exit)
break;
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);
632 printf(
" %d with %d bit %s\n",
Modes.stat_bit_fix[j], j+1, (j==0)?
"error":
"errors");
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);
644 printf(
" %d with %d bit %s\n",
Modes.stat_ph_bit_fix[j], j+1, (j==0)?
"error":
"errors");
647 printf(
"%d total usable messages\n",
Modes.stat_goodcrc +
Modes.stat_ph_goodcrc +
Modes.stat_fixed +
Modes.stat_ph_fixed);
650 if (
Modes.filename == NULL) {
651 rtlsdr_cancel_async(
Modes.dev);
652 rtlsdr_close(
Modes.dev);
654 pthread_cond_destroy(&
Modes.data_cond);
655 pthread_mutex_destroy(&
Modes.data_mutex);
656 pthread_join(
Modes.reader_thread,NULL);
void interactiveRemoveStaleAircrafts(void)
void detectModeS(uint16_t *m, uint32_t mlen)
void sigintHandler(int dummy)
void interactiveShowData(void)
void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx)
#define MODES_ICAO_CACHE_LEN
#define MODES_DEBUG_GOODCRC
#define MODES_DEFAULT_FREQ
#define MODES_ASYNC_BUF_NUMBER
#define MODES_NET_OUTPUT_SBS_PORT
#define MODES_PREAMBLE_SIZE
#define MODES_USER_LATITUDE_DFLT
void modesInitErrorInfo()
#define MODES_ASYNC_BUF_SIZE
#define MODES_RAWOUT_BUF_SIZE
void * readerThreadEntryPoint(void *arg)
#define MODES_USER_LONGITUDE_DFLT
#define MODES_INTERACTIVE_DISPLAY_TTL
#define MODES_NET_INPUT_RAW_PORT
int main(int argc, char *argv[])
void modesReadFromClients(void)
void backgroundTasks(void)
double abs(const SVector< n, T > &v)
#define MODES_DEFAULT_RATE
#define MODES_RAWOUT_BUF_RATE
#define MODES_NET_INPUT_BEAST_PORT
#define MODES_MAX_BITERRORS
#define MODES_INTERACTIVE_DELETE_TTL
#define MODES_DEBUG_DEMOD
#define MODES_DEBUG_DEMODERR
#define MODES_NET_OUTPUT_RAW_PORT
#define MODES_DEBUG_NOPREAMBLE
#define MODES_ASYNC_BUF_SAMPLES
#define MODES_DUMP1090_VERSION
void modesInitConfig(void)
void computeMagnitudeVector()
#define MODES_RAWOUT_BUF_FLUSH
#define MODES_USER_LATLON_VALID
#define MODES_LONG_MSG_SIZE
#define MODES_DEBUG_BADCRC
#define MODES_NET_OUTPUT_BEAST_PORT
#define MODES_NET_HTTP_PORT
void modesInitRTLSDR(void)
int aeraConnectToSocket(int *aeraSocketFD, char host[], int port)
#define MODES_INTERACTIVE_ROWS
void readDataFromFile(void)