1 /*
2  * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
3  * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <errno.h>
20 #include <signal.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #ifndef _WIN32
26 #include <unistd.h>
27 #else
28 #include <windows.h>
29 #include <io.h>
30 #include <fcntl.h>
31 #include "getopt/getopt.h"
32 #endif
33 
34 #include "rtl-sdr.h"
35 #include "convenience/convenience.h"
36 
37 #define DEFAULT_SAMPLE_RATE		2048000
38 #define DEFAULT_BUF_LENGTH		(16 * 16384)
39 #define MINIMAL_BUF_LENGTH		512
40 #define MAXIMAL_BUF_LENGTH		(256 * 16384)
41 
42 static int do_exit = 0;
43 static uint32_t bytes_to_read = 0;
44 static rtlsdr_dev_t *dev = NULL;
45 
usage(void)46 void usage(void)
47 {
48 	fprintf(stderr,
49 		"rtl_sdr, an I/Q recorder for RTL2832 based DVB-T receivers\n\n"
50 		"Usage:\t -f frequency_to_tune_to [Hz]\n"
51 		"\t[-s samplerate (default: 2048000 Hz)]\n"
52 		"\t[-d device_index (default: 0)]\n"
53 		"\t[-g gain (default: 0 for auto)]\n"
54 		"\t[-p ppm_error (default: 0)]\n"
55 		"\t[-b output_block_size (default: 16 * 16384)]\n"
56 		"\t[-n number of samples to read (default: 0, infinite)]\n"
57 		"\t[-S force sync output (default: async)]\n"
58 		"\tfilename (a '-' dumps samples to stdout)\n\n");
59 	exit(1);
60 }
61 
62 #ifdef _WIN32
63 BOOL WINAPI
sighandler(int signum)64 sighandler(int signum)
65 {
66 	if (CTRL_C_EVENT == signum) {
67 		fprintf(stderr, "Signal caught, exiting!\n");
68 		do_exit = 1;
69 		rtlsdr_cancel_async(dev);
70 		return TRUE;
71 	}
72 	return FALSE;
73 }
74 #else
sighandler(int signum)75 static void sighandler(int signum)
76 {
77 	fprintf(stderr, "Signal caught, exiting!\n");
78 	do_exit = 1;
79 	rtlsdr_cancel_async(dev);
80 }
81 #endif
82 
rtlsdr_callback(unsigned char * buf,uint32_t len,void * ctx)83 static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
84 {
85 	if (ctx) {
86 		if (do_exit)
87 			return;
88 
89 		if ((bytes_to_read > 0) && (bytes_to_read < len)) {
90 			len = bytes_to_read;
91 			do_exit = 1;
92 			rtlsdr_cancel_async(dev);
93 		}
94 
95 		if (fwrite(buf, 1, len, (FILE*)ctx) != len) {
96 			fprintf(stderr, "Short write, samples lost, exiting!\n");
97 			rtlsdr_cancel_async(dev);
98 		}
99 
100 		if (bytes_to_read > 0)
101 			bytes_to_read -= len;
102 	}
103 }
104 
main(int argc,char ** argv)105 int main(int argc, char **argv)
106 {
107 #ifndef _WIN32
108 	struct sigaction sigact;
109 #endif
110 	char *filename = NULL;
111 	int n_read;
112 	int r, opt;
113 	int gain = 0;
114 	int ppm_error = 0;
115 	int sync_mode = 0;
116 	FILE *file;
117 	uint8_t *buffer;
118 	int dev_index = 0;
119 	int dev_given = 0;
120 	uint32_t frequency = 100000000;
121 	uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
122 	uint32_t out_block_size = DEFAULT_BUF_LENGTH;
123 
124 	while ((opt = getopt(argc, argv, "d:f:g:s:b:n:p:S")) != -1) {
125 		switch (opt) {
126 		case 'd':
127 			dev_index = verbose_device_search(optarg);
128 			dev_given = 1;
129 			break;
130 		case 'f':
131 			frequency = (uint32_t)atofs(optarg);
132 			break;
133 		case 'g':
134 			gain = (int)(atof(optarg) * 10); /* tenths of a dB */
135 			break;
136 		case 's':
137 			samp_rate = (uint32_t)atofs(optarg);
138 			break;
139 		case 'p':
140 			ppm_error = atoi(optarg);
141 			break;
142 		case 'b':
143 			out_block_size = (uint32_t)atof(optarg);
144 			break;
145 		case 'n':
146 			bytes_to_read = (uint32_t)atof(optarg) * 2;
147 			break;
148 		case 'S':
149 			sync_mode = 1;
150 			break;
151 		default:
152 			usage();
153 			break;
154 		}
155 	}
156 
157 	if (argc <= optind) {
158 		usage();
159 	} else {
160 		filename = argv[optind];
161 	}
162 
163 	if(out_block_size < MINIMAL_BUF_LENGTH ||
164 	   out_block_size > MAXIMAL_BUF_LENGTH ){
165 		fprintf(stderr,
166 			"Output block size wrong value, falling back to default\n");
167 		fprintf(stderr,
168 			"Minimal length: %u\n", MINIMAL_BUF_LENGTH);
169 		fprintf(stderr,
170 			"Maximal length: %u\n", MAXIMAL_BUF_LENGTH);
171 		out_block_size = DEFAULT_BUF_LENGTH;
172 	}
173 
174 	buffer = malloc(out_block_size * sizeof(uint8_t));
175 
176 	if (!dev_given) {
177 		dev_index = verbose_device_search("0");
178 	}
179 
180 	if (dev_index < 0) {
181 		exit(1);
182 	}
183 
184 	r = rtlsdr_open(&dev, (uint32_t)dev_index);
185 	if (r < 0) {
186 		fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
187 		exit(1);
188 	}
189 #ifndef _WIN32
190 	sigact.sa_handler = sighandler;
191 	sigemptyset(&sigact.sa_mask);
192 	sigact.sa_flags = 0;
193 	sigaction(SIGINT, &sigact, NULL);
194 	sigaction(SIGTERM, &sigact, NULL);
195 	sigaction(SIGQUIT, &sigact, NULL);
196 	sigaction(SIGPIPE, &sigact, NULL);
197 #else
198 	SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
199 #endif
200 	/* Set the sample rate */
201 	verbose_set_sample_rate(dev, samp_rate);
202 
203 	/* Set the frequency */
204 	verbose_set_frequency(dev, frequency);
205 
206 	if (0 == gain) {
207 		 /* Enable automatic gain */
208 		verbose_auto_gain(dev);
209 	} else {
210 		/* Enable manual gain */
211 		gain = nearest_gain(dev, gain);
212 		verbose_gain_set(dev, gain);
213 	}
214 
215 	verbose_ppm_set(dev, ppm_error);
216 
217 	if(strcmp(filename, "-") == 0) { /* Write samples to stdout */
218 		file = stdout;
219 #ifdef _WIN32
220 		_setmode(_fileno(stdin), _O_BINARY);
221 #endif
222 	} else {
223 		file = fopen(filename, "wb");
224 		if (!file) {
225 			fprintf(stderr, "Failed to open %s\n", filename);
226 			goto out;
227 		}
228 	}
229 
230 	/* Reset endpoint before we start reading from it (mandatory) */
231 	verbose_reset_buffer(dev);
232 
233 	if (sync_mode) {
234 		fprintf(stderr, "Reading samples in sync mode...\n");
235 		while (!do_exit) {
236 			r = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read);
237 			if (r < 0) {
238 				fprintf(stderr, "WARNING: sync read failed.\n");
239 				break;
240 			}
241 
242 			if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t)n_read)) {
243 				n_read = bytes_to_read;
244 				do_exit = 1;
245 			}
246 
247 			if (fwrite(buffer, 1, n_read, file) != (size_t)n_read) {
248 				fprintf(stderr, "Short write, samples lost, exiting!\n");
249 				break;
250 			}
251 
252 			if ((uint32_t)n_read < out_block_size) {
253 				fprintf(stderr, "Short read, samples lost, exiting!\n");
254 				break;
255 			}
256 
257 			if (bytes_to_read > 0)
258 				bytes_to_read -= n_read;
259 		}
260 	} else {
261 		fprintf(stderr, "Reading samples in async mode...\n");
262 		r = rtlsdr_read_async(dev, rtlsdr_callback, (void *)file,
263 				      0, out_block_size);
264 	}
265 
266 	if (do_exit)
267 		fprintf(stderr, "\nUser cancel, exiting...\n");
268 	else
269 		fprintf(stderr, "\nLibrary error %d, exiting...\n", r);
270 
271 	if (file != stdout)
272 		fclose(file);
273 
274 	rtlsdr_close(dev);
275 	free (buffer);
276 out:
277 	return r >= 0 ? r : -r;
278 }
279