/* * Copyright (C) 2012 by Kyle Keen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include typedef void* rtlsdr_dev_t; #include "convenience.h" #include "rtl_ais.h" void usage(void) { fprintf(stderr, "rtl_ais, a simple AIS tuner\n" "\t and generic dual-frequency FM demodulator\n\n" "(probably not a good idea to use with e4000 tuners)\n" "Use: rtl_ais [options] [outputfile]\n" "\t[-l left_frequency (default: 161.975M)]\n" "\t[-r right_frequency (default: 162.025M)]\n" "\t left freq < right freq\n" "\t frequencies must be within 1.2MHz\n" "\t[-s sample_rate (default: 24k)]\n" "\t maximum value, might be down to 12k\n" "\t[-o output_rate (default: 48k)]\n" "\t must be equal or greater than twice -s value\n" "\t[-E toggle edge tuning (default: off)]\n" "\t[-D toggle DC filter (default: on)]\n" //"\t[-O toggle oversampling (default: off)\n" "\t[-d device_index (default: 0)]\n" "\t[-g tuner_gain (default: automatic)]\n" "\t[-p ppm_error (default: 0)]\n" "\t[-R enable RTL chip AGC (default: off)]\n" "\t[-A turn off built-in AIS decoder (default: on)]\n" "\t use this option to output samples to file or stdout.\n" "\tBuilt-in AIS decoder options:\n" "\t[-h host (default: 127.0.0.1)]\n" "\t[-P port (default: 10110)]\n" "\t[-T use TCP communication, rtl-ais is tcp server ( -h is ignored)\n" "\t[-t time to keep ais messages in sec, using tcp listener (default: 15)\n" "\t[-n log NMEA sentences to console (stderr) (default off)]\n" "\t[-I add sample index to NMEA messages (default off)]\n" "\t[-L log sound levels to console (stderr) (default off)]\n\n" "\t[-S seconds_for_decoder_stats (default 0=off)]\n\n" "\tWhen the built-in AIS decoder is disabled the samples are sent to\n" "\tto [outputfile] (a '-' dumps samples to stdout)\n" "\t omitting the filename also uses stdout\n\n" "\tOutput is stereo 2x16 bit signed ints\n\n" "\tExamples:\n" "\tReceive AIS traffic,sent UDP NMEA sentences to 127.0.0.1 port 10110\n" "\t and log the senteces to console:\n\n" "\trtl_ais -n\n\n" "\tTune two fm stations and play one on each channel:\n\n" "\trtl_ais -l233.15M -r233.20M -A | play -r48k -traw -es -b16 -c2 -V1 - " "\n"); exit(1); } static volatile int do_exit = 0; static void sighandler(int signum) { signum = signum; fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; } int main(int argc, char **argv) { #ifndef WIN32 struct sigaction sigact; sigact.sa_handler = sighandler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGPIPE, &sigact, NULL); #else signal(SIGINT, sighandler); signal(SIGTERM, sighandler); #endif int opt; struct rtl_ais_config config; rtl_ais_default_config(&config); config.host = strdup("127.0.0.1"); config.port = strdup("10110"); while ((opt = getopt(argc, argv, "l:r:s:o:EODd:g:p:RATIt:P:h:nLS:?")) != -1) { switch (opt) { case 'l': config.left_freq = (int)atofs(optarg); break; case 'r': config.right_freq = (int)atofs(optarg); break; case 's': config.sample_rate = (int)atofs(optarg); break; case 'o': config.output_rate = (int)atofs(optarg); break; case 'E': config.edge = !config.edge; break; case 'D': config.dc_filter = !config.dc_filter; break; case 'O': config.oversample = !config.oversample; break; case 'd': config.dev_index = verbose_device_search(optarg); config.dev_given = 1; break; case 'g': config.gain = (int)(atof(optarg) * 10); break; case 'p': config.ppm_error = atoi(optarg); config.custom_ppm = 1; break; case 'R': config.rtl_agc=1; break; case 'A': config.use_internal_aisdecoder=0; break; case 'I': config.add_sample_num = 1; break; case 'P': config.port=strdup(optarg); break; case 'T': config.use_tcp_listener=1; break; case 't': config.tcp_keep_ais_time = atoi(optarg); break; case 'h': config.host=strdup(optarg); break; case 'L': config.show_levels=1; break; case 'S': config.seconds_for_decoder_stats=atoi(optarg); break; case 'n': config.debug_nmea = 1; break; case '?': default: usage(); return 2; } } if (argc <= optind) { config.filename = "-"; } else { config.filename = argv[optind]; } if (config.edge) { fprintf(stderr, "Edge tuning enabled.\n"); } else { fprintf(stderr, "Edge tuning disabled.\n"); } if (config.dc_filter) { fprintf(stderr, "DC filter enabled.\n"); } else { fprintf(stderr, "DC filter disabled.\n"); } if (config.rtl_agc) { fprintf(stderr, "RTL AGC enabled.\n"); } else { fprintf(stderr, "RTL AGC disabled.\n"); } if (config.use_internal_aisdecoder) { fprintf(stderr, "Internal AIS decoder enabled.\n"); } else { fprintf(stderr, "Internal AIS decoder disabled.\n"); } struct rtl_ais_context *ctx = rtl_ais_start(&config); if(!ctx) { fprintf(stderr, "\nrtl_ais_start failed, exiting...\n"); exit(1); } /* aidecoder.c appends the messages to a queue that can be used for a routine if rtl_ais is compiled as lib. Here we only loop and dequeue the messages, and the puts() sentence that print the message is commented out. If the -n parameter is used the messages are printed from nmea_sentence_received() in aidecoder.c */ while(!do_exit && rtl_ais_isactive(ctx)) { #if _POSIX_C_SOURCE >= 199309L // nanosleep available() struct timespec five = { 0, 50 * 1000 * 1000}; #endif const char *str; if(config.use_internal_aisdecoder) { // dequeue while((str = rtl_ais_next_message(ctx))) { //puts(str); or code something that fits your needs } } #if _POSIX_C_SOURCE >= 199309L // nanosleep available() nanosleep(&five, NULL); #else usleep(50000); #endif } rtl_ais_cleanup(ctx); return 0; }