unsigned short checkButtons() { unsigned short state; unsigned int cnt; buttons = ~PORTB & 0x07; state = buttons; cnt = 0; // Debounce switches. while (state != 0) { // Allow multi-press buttons to "pile-on". if ( num_bits_set[state] > num_bits_set[buttons] ) { buttons = state; } delay_ms(1); backgroundTasks(); state = ~PORTB & 0x07; // Indicate long button press. if (cnt++ > 1000) { buttons = buttons | 0x08; break; } } // Note, we exit early on a long press and the user may still have his finger // on the button. The calling routine needs to deal with this! return buttons; }
// Wait for all buttons to be released void waitButtonRelease() { buttons = ~PORTB & 0x07; while (buttons != 0) { delay_ms(1); backgroundTasks(); buttons = ~PORTB & 0x07; } }
// //========================================================================= // int main(int argc, char **argv) { int j; // Set sane defaults modesInitConfig(); signal(SIGINT, sigintHandler); // Define Ctrl/C handler (exit program) // Parse the command line options for (j = 1; j < argc; j++) { int more = j+1 < argc; // There are more arguments if (!strcmp(argv[j],"--device-index") && more) { Modes.dev_index = atoi(argv[++j]); } else if (!strcmp(argv[j],"--gain") && more) { Modes.gain = (int) atof(argv[++j])*10; // Gain is in tens of DBs } else if (!strcmp(argv[j],"--enable-agc")) { Modes.enable_agc++; } else if (!strcmp(argv[j],"--freq") && more) { Modes.freq = (int) strtoll(argv[++j],NULL,10); } else if (!strcmp(argv[j],"--ifile") && more) { Modes.filename = strdup(argv[++j]); } else if (!strcmp(argv[j],"--fix")) { Modes.nfix_crc = 1; } else if (!strcmp(argv[j],"--no-fix")) { Modes.nfix_crc = 0; } else if (!strcmp(argv[j],"--no-crc-check")) { Modes.check_crc = 0; } else if (!strcmp(argv[j],"--phase-enhance")) { Modes.phase_enhance = 1; } else if (!strcmp(argv[j],"--raw")) { Modes.raw = 1; } else if (!strcmp(argv[j],"--net")) { Modes.net = 1; } else if (!strcmp(argv[j],"--modeac")) { Modes.mode_ac = 1; } else if (!strcmp(argv[j],"--net-beast")) { Modes.beast = 1; } else if (!strcmp(argv[j],"--net-only")) { Modes.net = 1; Modes.net_only = 1; } else if (!strcmp(argv[j],"--net-heartbeat") && more) { Modes.net_heartbeat_rate = atoi(argv[++j]) * 15; } else if (!strcmp(argv[j],"--net-ro-size") && more) { Modes.net_output_raw_size = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-ro-rate") && more) { Modes.net_output_raw_rate = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-ro-port") && more) { if (Modes.beast) // Required for legacy backward compatibility {Modes.net_output_beast_port = atoi(argv[++j]);;} else {Modes.net_output_raw_port = atoi(argv[++j]);} } else if (!strcmp(argv[j],"--net-ri-port") && more) { Modes.net_input_raw_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bo-port") && more) { Modes.net_output_beast_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bi-port") && more) { Modes.net_input_beast_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-http-port") && more) { Modes.net_http_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-sbs-port") && more) { Modes.net_output_sbs_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--onlyaddr")) { Modes.onlyaddr = 1; } else if (!strcmp(argv[j],"--metric")) { Modes.metric = 1; } else if (!strcmp(argv[j],"--aggressive")) { Modes.nfix_crc = MODES_MAX_BITERRORS; } else if (!strcmp(argv[j],"--interactive")) { Modes.interactive = 1; } else if (!strcmp(argv[j],"--interactive-rows") && more) { Modes.interactive_rows = atoi(argv[++j]); } else if (!strcmp(argv[j],"--interactive-ttl") && more) { Modes.interactive_display_ttl = atoi(argv[++j]); } else if (!strcmp(argv[j],"--lat") && more) { Modes.fUserLat = atof(argv[++j]); } else if (!strcmp(argv[j],"--lon") && more) { Modes.fUserLon = atof(argv[++j]); } else if (!strcmp(argv[j],"--debug") && more) { char *f = argv[++j]; while(*f) { switch(*f) { case 'D': Modes.debug |= MODES_DEBUG_DEMOD; break; case 'd': Modes.debug |= MODES_DEBUG_DEMODERR; break; case 'C': Modes.debug |= MODES_DEBUG_GOODCRC; break; case 'c': Modes.debug |= MODES_DEBUG_BADCRC; break; case 'p': Modes.debug |= MODES_DEBUG_NOPREAMBLE; break; case 'n': Modes.debug |= MODES_DEBUG_NET; break; case 'j': Modes.debug |= MODES_DEBUG_JS; break; default: fprintf(stderr, "Unknown debugging flag: %c\n", *f); exit(1); break; } f++; } } else if (!strcmp(argv[j],"--stats")) { Modes.stats = 1; } else if (!strcmp(argv[j],"--snip") && more) { snipMode(atoi(argv[++j])); exit(0); } else if (!strcmp(argv[j],"--help")) { showHelp(); exit(0); } else if (!strcmp(argv[j],"--ppm") && more) { Modes.ppm_error = atoi(argv[++j]); } else if (!strcmp(argv[j],"--quiet")) { Modes.quiet = 1; } else if (!strcmp(argv[j],"--mlat")) { Modes.mlat = 1; } else if (!strcmp(argv[j],"--interactive-rtl1090")) { Modes.interactive = 1; Modes.interactive_rtl1090 = 1; } else { fprintf(stderr, "Unknown or not enough arguments for option '%s'.\n\n", argv[j]); showHelp(); exit(1); } } #ifndef _WIN32 // Setup for SIGWINCH for handling lines if (Modes.interactive) {signal(SIGWINCH, sigWinchCallback);} #endif // Initialization modesInit(); if (Modes.net_only) { fprintf(stderr,"Net-only mode, no RTL device or file open.\n"); } else if (Modes.filename == NULL) { modesInitRTLSDR(); } else { if (Modes.filename[0] == '-' && Modes.filename[1] == '\0') { Modes.fd = STDIN_FILENO; } else if ((Modes.fd = open(Modes.filename,O_RDONLY)) == -1) { perror("Opening data file"); exit(1); } } if (Modes.net) modesInitNet(); // If the user specifies --net-only, just run in order to serve network // clients without reading data from the RTL device while (Modes.net_only) { if (Modes.exit) exit(0); // If we exit net_only nothing further in main() backgroundTasks(); usleep(100000); } // Create the thread that will read the data from the device. pthread_create(&Modes.reader_thread, NULL, readerThreadEntryPoint, NULL); pthread_mutex_lock(&Modes.data_mutex); while (Modes.exit == 0) { if (Modes.iDataReady == 0) { pthread_cond_wait(&Modes.data_cond,&Modes.data_mutex); // This unlocks Modes.data_mutex, and waits for Modes.data_cond continue; // Once (Modes.data_cond) occurs, it locks Modes.data_mutex } // Modes.data_mutex is Locked, and (Modes.iDataReady != 0) if (Modes.iDataReady) { // Check we have new data, just in case!! Modes.iDataOut &= (MODES_ASYNC_BUF_NUMBER-1); // Just incase // Translate the next lot of I/Q samples into Modes.magnitude computeMagnitudeVector(Modes.pData[Modes.iDataOut]); Modes.stSystemTimeBlk = Modes.stSystemTimeRTL[Modes.iDataOut]; // Update the input buffer pointer queue Modes.iDataOut = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataOut + 1); Modes.iDataReady = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataIn - Modes.iDataOut); // If we lost some blocks, correct the timestamp if (Modes.iDataLost) { Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES * 6 * Modes.iDataLost); Modes.iDataLost = 0; } // It's safe to release the lock now pthread_cond_signal (&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); // Process data after releasing the lock, so that the capturing // thread can read data while we perform computationally expensive // stuff at the same time. detectModeS(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES); // Update the timestamp ready for the next block Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES*6); } else { pthread_cond_signal (&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); } backgroundTasks(); pthread_mutex_lock(&Modes.data_mutex); } // If --stats were given, print statistics if (Modes.stats) { printf("\n\n"); if (Modes.interactive) interactiveShowData(); printf("%d ModeA/C detected\n", Modes.stat_ModeAC); printf("%d valid Mode-S preambles\n", Modes.stat_valid_preamble); printf("%d DF-?? fields corrected for length\n", Modes.stat_DF_Len_Corrected); printf("%d DF-?? fields corrected for type\n", Modes.stat_DF_Type_Corrected); printf("%d demodulated with 0 errors\n", Modes.stat_demodulated0); printf("%d demodulated with 1 error\n", Modes.stat_demodulated1); printf("%d demodulated with 2 errors\n", Modes.stat_demodulated2); printf("%d demodulated with > 2 errors\n", Modes.stat_demodulated3); printf("%d with good crc\n", Modes.stat_goodcrc); printf("%d with bad crc\n", Modes.stat_badcrc); printf("%d errors corrected\n", Modes.stat_fixed); for (j = 0; j < MODES_MAX_BITERRORS; j++) { printf(" %d with %d bit %s\n", Modes.stat_bit_fix[j], j+1, (j==0)?"error":"errors"); } if (Modes.phase_enhance) { printf("%d phase enhancement attempts\n", Modes.stat_out_of_phase); printf("%d phase enhanced demodulated with 0 errors\n", Modes.stat_ph_demodulated0); printf("%d phase enhanced demodulated with 1 error\n", Modes.stat_ph_demodulated1); printf("%d phase enhanced demodulated with 2 errors\n", Modes.stat_ph_demodulated2); printf("%d phase enhanced demodulated with > 2 errors\n", Modes.stat_ph_demodulated3); printf("%d phase enhanced with good crc\n", Modes.stat_ph_goodcrc); printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc); printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed); for (j = 0; j < MODES_MAX_BITERRORS; j++) { printf(" %d with %d bit %s\n", Modes.stat_ph_bit_fix[j], j+1, (j==0)?"error":"errors"); } } printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed); } if (Modes.filename == NULL) { rtlsdr_cancel_async(Modes.dev); // Cancel rtlsdr_read_async will cause data input thread to terminate cleanly rtlsdr_close(Modes.dev); } pthread_cond_destroy(&Modes.data_cond); // Thread cleanup pthread_mutex_destroy(&Modes.data_mutex); pthread_join(Modes.reader_thread,NULL); // Wait on reader thread exit #ifndef _WIN32 pthread_exit(0); #else return (0); #endif }
// //========================================================================= // int main(int argc, char **argv) { int j; int stdout_option = 0; char *bo_connect_ipaddr = "127.0.0.1"; int bo_connect_port = MODES_NET_OUTPUT_BEAST_PORT; struct client *c; struct net_service *beast_input, *fatsv_output; // Set sane defaults faupInitConfig(); // Parse the command line options for (j = 1; j < argc; j++) { int more = j+1 < argc; // There are more arguments if (!strcmp(argv[j],"--net-bo-port") && more) { bo_connect_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bo-ipaddr") && more) { bo_connect_ipaddr = argv[++j]; } else if (!strcmp(argv[j],"--lat") && more) { Modes.fUserLat = atof(argv[++j]); } else if (!strcmp(argv[j],"--lon") && more) { Modes.fUserLon = atof(argv[++j]); } else if (!strcmp(argv[j],"--max-range") && more) { Modes.maxRange = atof(argv[++j]) * 1852.0; // convert to metres } else if (!strcmp(argv[j],"--help")) { showHelp(); exit(0); } else if (!strcmp(argv[j],"--stdout")) { stdout_option = 1; } else { fprintf(stderr, "Unknown or not enough arguments for option '%s'.\n\n", argv[j]); showHelp(); exit(1); } } if (!stdout_option) { fprintf(stderr, "--stdout is required, output always goes to stdout.\n"); showHelp(); exit(1); } // Initialization faupInit(); modesInitNet(); // Set up input connection beast_input = makeBeastInputService(); c = serviceConnect(beast_input, bo_connect_ipaddr, bo_connect_port); if (!c) { fprintf (stderr, "faup1090: failed to connect to %s:%d (is dump1090 running?): %s\n", bo_connect_ipaddr, bo_connect_port, Modes.aneterr); exit (1); } // Set up output connection on stdout fatsv_output = makeFatsvOutputService(); createGenericClient(fatsv_output, STDOUT_FILENO); // Run it until we've lost either connection while (!Modes.exit && beast_input->connections && fatsv_output->connections) { backgroundTasks(); usleep(100000); } return 0; }
// //========================================================================= // int main(int argc, char **argv) { int j; // Set sane defaults modesInitConfig(); // signal handlers: signal(SIGINT, sigintHandler); signal(SIGTERM, sigtermHandler); // Parse the command line options for (j = 1; j < argc; j++) { int more = j+1 < argc; // There are more arguments if (!strcmp(argv[j],"--device-index") && more) { Modes.dev_name = strdup(argv[++j]); } else if (!strcmp(argv[j],"--gain") && more) { Modes.gain = (int) (atof(argv[++j])*10); // Gain is in tens of DBs } else if (!strcmp(argv[j],"--enable-agc")) { Modes.enable_agc++; } else if (!strcmp(argv[j],"--freq") && more) { Modes.freq = (int) strtoll(argv[++j],NULL,10); } else if (!strcmp(argv[j],"--ifile") && more) { Modes.filename = strdup(argv[++j]); } else if (!strcmp(argv[j],"--iformat") && more) { ++j; if (!strcasecmp(argv[j], "uc8")) { Modes.input_format = INPUT_UC8; } else if (!strcasecmp(argv[j], "sc16")) { Modes.input_format = INPUT_SC16; } else if (!strcasecmp(argv[j], "sc16q11")) { Modes.input_format = INPUT_SC16Q11; } else { fprintf(stderr, "Input format '%s' not understood (supported values: UC8, SC16, SC16Q11)\n", argv[j]); exit(1); } } else if (!strcmp(argv[j],"--dcfilter")) { Modes.dc_filter = 1; } else if (!strcmp(argv[j],"--measure-noise")) { Modes.measure_noise = 1; } else if (!strcmp(argv[j],"--fix")) { Modes.nfix_crc = 1; } else if (!strcmp(argv[j],"--no-fix")) { Modes.nfix_crc = 0; } else if (!strcmp(argv[j],"--no-crc-check")) { Modes.check_crc = 0; } else if (!strcmp(argv[j],"--phase-enhance")) { Modes.phase_enhance = 1; } else if (!strcmp(argv[j],"--raw")) { Modes.raw = 1; } else if (!strcmp(argv[j],"--net")) { Modes.net = 1; } else if (!strcmp(argv[j],"--modeac")) { Modes.mode_ac = 1; } else if (!strcmp(argv[j],"--net-beast")) { Modes.beast = 1; } else if (!strcmp(argv[j],"--net-only")) { Modes.net = 1; Modes.net_only = 1; } else if (!strcmp(argv[j],"--net-heartbeat") && more) { Modes.net_heartbeat_interval = (uint64_t)(1000 * atof(argv[++j])); } else if (!strcmp(argv[j],"--net-ro-size") && more) { Modes.net_output_flush_size = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-ro-rate") && more) { Modes.net_output_flush_interval = 1000 * atoi(argv[++j]) / 15; // backwards compatibility } else if (!strcmp(argv[j],"--net-ro-interval") && more) { Modes.net_output_flush_interval = (uint64_t)(1000 * atof(argv[++j])); } else if (!strcmp(argv[j],"--net-ro-port") && more) { if (Modes.beast) // Required for legacy backward compatibility {Modes.net_output_beast_port = atoi(argv[++j]);;} else {Modes.net_output_raw_port = atoi(argv[++j]);} } else if (!strcmp(argv[j],"--net-ri-port") && more) { Modes.net_input_raw_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bo-port") && more) { Modes.net_output_beast_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bi-port") && more) { Modes.net_input_beast_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bind-address") && more) { Modes.net_bind_address = strdup(argv[++j]); } else if (!strcmp(argv[j],"--net-http-port") && more) { Modes.net_http_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-fatsv-port") && more) { Modes.net_fatsv_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-sbs-port") && more) { Modes.net_output_sbs_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-buffer") && more) { Modes.net_sndbuf_size = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-verbatim")) { Modes.net_verbatim = 1; } else if (!strcmp(argv[j],"--forward-mlat")) { Modes.forward_mlat = 1; } else if (!strcmp(argv[j],"--onlyaddr")) { Modes.onlyaddr = 1; } else if (!strcmp(argv[j],"--metric")) { Modes.metric = 1; } else if (!strcmp(argv[j],"--aggressive")) { Modes.nfix_crc = MODES_MAX_BITERRORS; } else if (!strcmp(argv[j],"--interactive")) { Modes.interactive = Modes.throttle = 1; } else if (!strcmp(argv[j],"--throttle")) { Modes.throttle = 1; } else if (!strcmp(argv[j],"--interactive-rows") && more) { Modes.interactive_rows = atoi(argv[++j]); } else if (!strcmp(argv[j],"--interactive-ttl") && more) { Modes.interactive_display_ttl = (uint64_t)(1000 * atof(argv[++j])); } else if (!strcmp(argv[j],"--lat") && more) { Modes.fUserLat = atof(argv[++j]); } else if (!strcmp(argv[j],"--lon") && more) { Modes.fUserLon = atof(argv[++j]); } else if (!strcmp(argv[j],"--max-range") && more) { Modes.maxRange = atof(argv[++j]) * 1852.0; // convert to metres } else if (!strcmp(argv[j],"--debug") && more) { char *f = argv[++j]; while(*f) { switch(*f) { case 'D': Modes.debug |= MODES_DEBUG_DEMOD; break; case 'd': Modes.debug |= MODES_DEBUG_DEMODERR; break; case 'C': Modes.debug |= MODES_DEBUG_GOODCRC; break; case 'c': Modes.debug |= MODES_DEBUG_BADCRC; break; case 'p': Modes.debug |= MODES_DEBUG_NOPREAMBLE; break; case 'n': Modes.debug |= MODES_DEBUG_NET; break; case 'j': Modes.debug |= MODES_DEBUG_JS; break; default: fprintf(stderr, "Unknown debugging flag: %c\n", *f); exit(1); break; } f++; } } else if (!strcmp(argv[j],"--stats")) { if (!Modes.stats) Modes.stats = (uint64_t)1 << 60; // "never" } else if (!strcmp(argv[j],"--stats-range")) { Modes.stats_range_histo = 1; } else if (!strcmp(argv[j],"--stats-every") && more) { Modes.stats = (uint64_t) (1000 * atof(argv[++j])); } else if (!strcmp(argv[j],"--snip") && more) { snipMode(atoi(argv[++j])); exit(0); } else if (!strcmp(argv[j],"--help")) { showHelp(); exit(0); } else if (!strcmp(argv[j],"--ppm") && more) { Modes.ppm_error = atoi(argv[++j]); } else if (!strcmp(argv[j],"--quiet")) { Modes.quiet = 1; } else if (!strcmp(argv[j],"--show-only") && more) { Modes.show_only = (uint32_t) strtoul(argv[++j], NULL, 16); } else if (!strcmp(argv[j],"--mlat")) { Modes.mlat = 1; } else if (!strcmp(argv[j],"--interactive-rtl1090")) { Modes.interactive = 1; Modes.interactive_rtl1090 = 1; } else if (!strcmp(argv[j],"--oversample")) { Modes.oversample = 1; #ifndef _WIN32 } else if (!strcmp(argv[j], "--write-json") && more) { Modes.json_dir = strdup(argv[++j]); } else if (!strcmp(argv[j], "--write-json-every") && more) { Modes.json_interval = (uint64_t)(1000 * atof(argv[++j])); if (Modes.json_interval < 100) // 0.1s Modes.json_interval = 100; } else if (!strcmp(argv[j], "--json-location-accuracy") && more) { Modes.json_location_accuracy = atoi(argv[++j]); #endif } else { fprintf(stderr, "Unknown or not enough arguments for option '%s'.\n\n", argv[j]); showHelp(); exit(1); } } #ifndef _WIN32 // Setup for SIGWINCH for handling lines if (Modes.interactive) {signal(SIGWINCH, sigWinchCallback);} #endif if (Modes.mode_ac && Modes.oversample) { fprintf(stderr, "Warning: --modeac is currently ignored when --oversample is used;\n" " no ModeA/C messages will be decoded.\n"); } // Initialization log_with_timestamp("%s %s starting up.", MODES_DUMP1090_VARIANT, MODES_DUMP1090_VERSION); modesInit(); if (Modes.net_only) { fprintf(stderr,"Net-only mode, no RTL device or file open.\n"); } else if (Modes.filename == NULL) { if (modesInitRTLSDR() < 0) { exit(1); } } else { if (Modes.filename[0] == '-' && Modes.filename[1] == '\0') { Modes.fd = STDIN_FILENO; } else if ((Modes.fd = open(Modes.filename, #ifdef _WIN32 (O_RDONLY | O_BINARY) #else (O_RDONLY) #endif )) == -1) { perror("Opening data file"); exit(1); } } if (Modes.net) modesInitNet(); // init stats: Modes.stats_current.start = Modes.stats_current.end = Modes.stats_alltime.start = Modes.stats_alltime.end = Modes.stats_periodic.start = Modes.stats_periodic.end = Modes.stats_5min.start = Modes.stats_5min.end = Modes.stats_15min.start = Modes.stats_15min.end = mstime(); for (j = 0; j < 15; ++j) Modes.stats_1min[j].start = Modes.stats_1min[j].end = Modes.stats_current.start; // write initial json files so they're not missing writeJsonToFile("receiver.json", generateReceiverJson); writeJsonToFile("stats.json", generateStatsJson); writeJsonToFile("aircraft.json", generateAircraftJson); // If the user specifies --net-only, just run in order to serve network // clients without reading data from the RTL device if (Modes.net_only) { while (!Modes.exit) { struct timespec start_time; start_cpu_timing(&start_time); backgroundTasks(); end_cpu_timing(&start_time, &Modes.stats_current.background_cpu); usleep(100000); } } else { // Create the thread that will read the data from the device. pthread_mutex_lock(&Modes.data_mutex); pthread_create(&Modes.reader_thread, NULL, readerThreadEntryPoint, NULL); while (Modes.exit == 0) { struct timespec start_time; if (Modes.first_free_buffer == Modes.first_filled_buffer) { /* wait for more data. * we should be getting data every 50-60ms. wait for max 100ms before we give up and do some background work. * this is fairly aggressive as all our network I/O runs out of the background work! */ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_nsec += 100000000; normalize_timespec(&ts); pthread_cond_timedwait(&Modes.data_cond, &Modes.data_mutex, &ts); // This unlocks Modes.data_mutex, and waits for Modes.data_cond } // Modes.data_mutex is locked, and possibly we have data. // copy out reader CPU time and reset it add_timespecs(&Modes.reader_cpu_accumulator, &Modes.stats_current.reader_cpu, &Modes.stats_current.reader_cpu); Modes.reader_cpu_accumulator.tv_sec = 0; Modes.reader_cpu_accumulator.tv_nsec = 0; if (Modes.first_free_buffer != Modes.first_filled_buffer) { // FIFO is not empty, process one buffer. struct mag_buf *buf; start_cpu_timing(&start_time); buf = &Modes.mag_buffers[Modes.first_filled_buffer]; // Process data after releasing the lock, so that the capturing // thread can read data while we perform computationally expensive // stuff at the same time. pthread_mutex_unlock(&Modes.data_mutex); if (Modes.oversample) { demodulate2400(buf); } else { demodulate2000(buf); } Modes.stats_current.samples_processed += buf->length; Modes.stats_current.samples_dropped += buf->dropped; end_cpu_timing(&start_time, &Modes.stats_current.demod_cpu); // Mark the buffer we just processed as completed. pthread_mutex_lock(&Modes.data_mutex); Modes.first_filled_buffer = (Modes.first_filled_buffer + 1) % MODES_MAG_BUFFERS; pthread_cond_signal(&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); } else { // Nothing to process this time around. pthread_mutex_unlock(&Modes.data_mutex); } start_cpu_timing(&start_time); backgroundTasks(); end_cpu_timing(&start_time, &Modes.stats_current.background_cpu); pthread_mutex_lock(&Modes.data_mutex); } pthread_mutex_unlock(&Modes.data_mutex); pthread_join(Modes.reader_thread,NULL); // Wait on reader thread exit pthread_cond_destroy(&Modes.data_cond); // Thread cleanup - only after the reader thread is dead! pthread_mutex_destroy(&Modes.data_mutex); } // If --stats were given, print statistics if (Modes.stats) { display_total_stats(); } cleanup_converter(Modes.converter_state); log_with_timestamp("Normal exit."); pthread_exit(0); #ifdef _WIN32 return (0); #endif }