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  * Copyright (C) 2012-2013 by Hoernchen <la@tfc-server.de>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <errno.h>
21 #include <signal.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #ifndef _WIN32
27 #include <unistd.h>
28 #include <arpa/inet.h>
29 #include <sys/socket.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/time.h>
33 #include <netinet/in.h>
34 #include <fcntl.h>
35 #else
36 #include <winsock2.h>
37 #include "getopt/getopt.h"
38 #endif
39 
40 #include <pthread.h>
41 
42 #include "rtl-sdr.h"
43 #include "convenience/convenience.h"
44 
45 #ifdef _WIN32
46 #pragma comment(lib, "ws2_32.lib")
47 
48 typedef int socklen_t;
49 
50 #else
51 #define closesocket close
52 #define SOCKADDR struct sockaddr
53 #define SOCKET int
54 #define SOCKET_ERROR -1
55 #endif
56 
57 static SOCKET s;
58 
59 static pthread_t tcp_worker_thread;
60 static pthread_t command_thread;
61 static pthread_cond_t exit_cond;
62 static pthread_mutex_t exit_cond_lock;
63 
64 static pthread_mutex_t ll_mutex;
65 static pthread_cond_t cond;
66 
67 struct llist {
68 	char *data;
69 	size_t len;
70 	struct llist *next;
71 };
72 
73 typedef struct { /* structure size must be multiple of 2 bytes */
74 	char magic[4];
75 	uint32_t tuner_type;
76 	uint32_t tuner_gain_count;
77 } dongle_info_t;
78 
79 static rtlsdr_dev_t *dev = NULL;
80 
81 static int enable_biastee = 0;
82 static int global_numq = 0;
83 static struct llist *ll_buffers = 0;
84 static int llbuf_num = 500;
85 
86 static volatile int do_exit = 0;
87 
usage(void)88 void usage(void)
89 {
90 	printf("rtl_tcp, an I/Q spectrum server for RTL2832 based DVB-T receivers\n\n"
91 		"Usage:\t[-a listen address]\n"
92 		"\t[-p listen port (default: 1234)]\n"
93 		"\t[-f frequency to tune to [Hz]]\n"
94 		"\t[-g gain (default: 0 for auto)]\n"
95 		"\t[-s samplerate in Hz (default: 2048000 Hz)]\n"
96 		"\t[-b number of buffers (default: 15, set by library)]\n"
97 		"\t[-n max number of linked list buffers to keep (default: 500)]\n"
98 		"\t[-d device index (default: 0)]\n"
99 		"\t[-P ppm_error (default: 0)]\n"
100 		"\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\n");
101 	exit(1);
102 }
103 
104 #ifdef _WIN32
gettimeofday(struct timeval * tv,void * ignored)105 int gettimeofday(struct timeval *tv, void* ignored)
106 {
107 	FILETIME ft;
108 	unsigned __int64 tmp = 0;
109 	if (NULL != tv) {
110 		GetSystemTimeAsFileTime(&ft);
111 		tmp |= ft.dwHighDateTime;
112 		tmp <<= 32;
113 		tmp |= ft.dwLowDateTime;
114 		tmp /= 10;
115 #ifdef _MSC_VER
116 		tmp -= 11644473600000000Ui64;
117 #else
118 		tmp -= 11644473600000000ULL;
119 #endif
120 		tv->tv_sec = (long)(tmp / 1000000UL);
121 		tv->tv_usec = (long)(tmp % 1000000UL);
122 	}
123 	return 0;
124 }
125 
126 BOOL WINAPI
sighandler(int signum)127 sighandler(int signum)
128 {
129 	if (CTRL_C_EVENT == signum) {
130 		fprintf(stderr, "Signal caught, exiting!\n");
131 		do_exit = 1;
132 		rtlsdr_cancel_async(dev);
133 		return TRUE;
134 	}
135 	return FALSE;
136 }
137 #else
sighandler(int signum)138 static void sighandler(int signum)
139 {
140 	fprintf(stderr, "Signal caught, exiting!\n");
141 	rtlsdr_cancel_async(dev);
142 	do_exit = 1;
143 }
144 #endif
145 
rtlsdr_callback(unsigned char * buf,uint32_t len,void * ctx)146 void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
147 {
148 	if(!do_exit) {
149 		struct llist *rpt = (struct llist*)malloc(sizeof(struct llist));
150 		rpt->data = (char*)malloc(len);
151 		memcpy(rpt->data, buf, len);
152 		rpt->len = len;
153 		rpt->next = NULL;
154 
155 		pthread_mutex_lock(&ll_mutex);
156 
157 		if (ll_buffers == NULL) {
158 			ll_buffers = rpt;
159 		} else {
160 			struct llist *cur = ll_buffers;
161 			int num_queued = 0;
162 
163 			while (cur->next != NULL) {
164 				cur = cur->next;
165 				num_queued++;
166 			}
167 
168 			if(llbuf_num && llbuf_num == num_queued-2){
169 				struct llist *curelem;
170 
171 				free(ll_buffers->data);
172 				curelem = ll_buffers->next;
173 				free(ll_buffers);
174 				ll_buffers = curelem;
175 			}
176 
177 			cur->next = rpt;
178 
179 			if (num_queued > global_numq)
180 				printf("ll+, now %d\n", num_queued);
181 			else if (num_queued < global_numq)
182 				printf("ll-, now %d\n", num_queued);
183 
184 			global_numq = num_queued;
185 		}
186 		pthread_cond_signal(&cond);
187 		pthread_mutex_unlock(&ll_mutex);
188 	}
189 }
190 
tcp_worker(void * arg)191 static void *tcp_worker(void *arg)
192 {
193 	struct llist *curelem,*prev;
194 	int bytesleft,bytessent, index;
195 	struct timeval tv= {1,0};
196 	struct timespec ts;
197 	struct timeval tp;
198 	fd_set writefds;
199 	int r = 0;
200 
201 	while(1) {
202 		if(do_exit)
203 			pthread_exit(0);
204 
205 		pthread_mutex_lock(&ll_mutex);
206 		gettimeofday(&tp, NULL);
207 		ts.tv_sec  = tp.tv_sec+5;
208 		ts.tv_nsec = tp.tv_usec * 1000;
209 		r = pthread_cond_timedwait(&cond, &ll_mutex, &ts);
210 		if(r == ETIMEDOUT) {
211 			pthread_mutex_unlock(&ll_mutex);
212 			printf("worker cond timeout\n");
213 			sighandler(0);
214 			pthread_exit(NULL);
215 		}
216 
217 		curelem = ll_buffers;
218 		ll_buffers = 0;
219 		pthread_mutex_unlock(&ll_mutex);
220 
221 		while(curelem != 0) {
222 			bytesleft = curelem->len;
223 			index = 0;
224 			bytessent = 0;
225 			while(bytesleft > 0) {
226 				FD_ZERO(&writefds);
227 				FD_SET(s, &writefds);
228 				tv.tv_sec = 1;
229 				tv.tv_usec = 0;
230 				r = select(s+1, NULL, &writefds, NULL, &tv);
231 				if(r) {
232 					bytessent = send(s,  &curelem->data[index], bytesleft, 0);
233 					bytesleft -= bytessent;
234 					index += bytessent;
235 				}
236 				if(bytessent == SOCKET_ERROR || do_exit) {
237 						printf("worker socket bye\n");
238 						sighandler(0);
239 						pthread_exit(NULL);
240 				}
241 			}
242 			prev = curelem;
243 			curelem = curelem->next;
244 			free(prev->data);
245 			free(prev);
246 		}
247 	}
248 }
249 
set_gain_by_index(rtlsdr_dev_t * _dev,unsigned int index)250 static int set_gain_by_index(rtlsdr_dev_t *_dev, unsigned int index)
251 {
252 	int res = 0;
253 	int* gains;
254 	int count = rtlsdr_get_tuner_gains(_dev, NULL);
255 
256 	if (count > 0 && (unsigned int)count > index) {
257 		gains = malloc(sizeof(int) * count);
258 		count = rtlsdr_get_tuner_gains(_dev, gains);
259 
260 		res = rtlsdr_set_tuner_gain(_dev, gains[index]);
261 
262 		free(gains);
263 	}
264 
265 	return res;
266 }
267 
268 #ifdef _WIN32
269 #define __attribute__(x)
270 #pragma pack(push, 1)
271 #endif
272 struct command{
273 	unsigned char cmd;
274 	unsigned int param;
275 }__attribute__((packed));
276 #ifdef _WIN32
277 #pragma pack(pop)
278 #endif
command_worker(void * arg)279 static void *command_worker(void *arg)
280 {
281 	int left, received = 0;
282 	fd_set readfds;
283 	struct command cmd={0, 0};
284 	struct timeval tv= {1, 0};
285 	int r = 0;
286 	uint32_t tmp;
287 
288 	while(1) {
289 		left=sizeof(cmd);
290 		while(left >0) {
291 			FD_ZERO(&readfds);
292 			FD_SET(s, &readfds);
293 			tv.tv_sec = 1;
294 			tv.tv_usec = 0;
295 			r = select(s+1, &readfds, NULL, NULL, &tv);
296 			if(r) {
297 				received = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0);
298 				left -= received;
299 			}
300 			if(received == SOCKET_ERROR || do_exit) {
301 				printf("comm recv bye\n");
302 				sighandler(0);
303 				pthread_exit(NULL);
304 			}
305 		}
306 		switch(cmd.cmd) {
307 		case 0x01:
308 			printf("set freq %d\n", ntohl(cmd.param));
309 			rtlsdr_set_center_freq(dev,ntohl(cmd.param));
310 			break;
311 		case 0x02:
312 			printf("set sample rate %d\n", ntohl(cmd.param));
313 			rtlsdr_set_sample_rate(dev, ntohl(cmd.param));
314 			break;
315 		case 0x03:
316 			printf("set gain mode %d\n", ntohl(cmd.param));
317 			rtlsdr_set_tuner_gain_mode(dev, ntohl(cmd.param));
318 			break;
319 		case 0x04:
320 			printf("set gain %d\n", ntohl(cmd.param));
321 			rtlsdr_set_tuner_gain(dev, ntohl(cmd.param));
322 			break;
323 		case 0x05:
324 			printf("set freq correction %d\n", ntohl(cmd.param));
325 			rtlsdr_set_freq_correction(dev, ntohl(cmd.param));
326 			break;
327 		case 0x06:
328 			tmp = ntohl(cmd.param);
329 			printf("set if stage %d gain %d\n", tmp >> 16, (short)(tmp & 0xffff));
330 			rtlsdr_set_tuner_if_gain(dev, tmp >> 16, (short)(tmp & 0xffff));
331 			break;
332 		case 0x07:
333 			printf("set test mode %d\n", ntohl(cmd.param));
334 			rtlsdr_set_testmode(dev, ntohl(cmd.param));
335 			break;
336 		case 0x08:
337 			printf("set agc mode %d\n", ntohl(cmd.param));
338 			rtlsdr_set_agc_mode(dev, ntohl(cmd.param));
339 			break;
340 		case 0x09:
341 			printf("set direct sampling %d\n", ntohl(cmd.param));
342 			rtlsdr_set_direct_sampling(dev, ntohl(cmd.param));
343 			break;
344 		case 0x0a:
345 			printf("set offset tuning %d\n", ntohl(cmd.param));
346 			rtlsdr_set_offset_tuning(dev, ntohl(cmd.param));
347 			break;
348 		case 0x0b:
349 			printf("set rtl xtal %d\n", ntohl(cmd.param));
350 			rtlsdr_set_xtal_freq(dev, ntohl(cmd.param), 0);
351 			break;
352 		case 0x0c:
353 			printf("set tuner xtal %d\n", ntohl(cmd.param));
354 			rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));
355 			break;
356 		case 0x0d:
357 			printf("set tuner gain by index %d\n", ntohl(cmd.param));
358 			set_gain_by_index(dev, ntohl(cmd.param));
359 			break;
360 		case 0x0e:
361 			printf("set bias tee %d\n", ntohl(cmd.param));
362 			rtlsdr_set_bias_tee(dev, (int)ntohl(cmd.param));
363 			break;
364 		default:
365 			break;
366 		}
367 		cmd.cmd = 0xff;
368 	}
369 }
370 
main(int argc,char ** argv)371 int main(int argc, char **argv)
372 {
373 	int r, opt, i;
374 	char* addr = "127.0.0.1";
375 	int port = 1234;
376 	uint32_t frequency = 100000000, samp_rate = 2048000;
377 	struct sockaddr_in local, remote;
378 	uint32_t buf_num = 0;
379 	int dev_index = 0;
380 	int dev_given = 0;
381 	int gain = 0;
382 	int ppm_error = 0;
383 	struct llist *curelem,*prev;
384 	pthread_attr_t attr;
385 	void *status;
386 	struct timeval tv = {1,0};
387 	struct linger ling = {1,0};
388 	SOCKET listensocket;
389 	socklen_t rlen;
390 	fd_set readfds;
391 	u_long blockmode = 1;
392 	dongle_info_t dongle_info;
393 #ifdef _WIN32
394 	WSADATA wsd;
395 	i = WSAStartup(MAKEWORD(2,2), &wsd);
396 #else
397 	struct sigaction sigact, sigign;
398 #endif
399 
400 	while ((opt = getopt(argc, argv, "a:p:f:g:s:b:n:d:P:T")) != -1) {
401 		switch (opt) {
402 		case 'd':
403 			dev_index = verbose_device_search(optarg);
404 			dev_given = 1;
405 			break;
406 		case 'f':
407 			frequency = (uint32_t)atofs(optarg);
408 			break;
409 		case 'g':
410 			gain = (int)(atof(optarg) * 10); /* tenths of a dB */
411 			break;
412 		case 's':
413 			samp_rate = (uint32_t)atofs(optarg);
414 			break;
415 		case 'a':
416 			addr = optarg;
417 			break;
418 		case 'p':
419 			port = atoi(optarg);
420 			break;
421 		case 'b':
422 			buf_num = atoi(optarg);
423 			break;
424 		case 'n':
425 			llbuf_num = atoi(optarg);
426 			break;
427 		case 'P':
428 			ppm_error = atoi(optarg);
429 			break;
430 		case 'T':
431 			enable_biastee = 1;
432 			break;
433 		default:
434 			usage();
435 			break;
436 		}
437 	}
438 
439 	if (argc < optind)
440 		usage();
441 
442 	if (!dev_given) {
443 		dev_index = verbose_device_search("0");
444 	}
445 
446 	if (dev_index < 0) {
447 	    exit(1);
448 	}
449 
450 	rtlsdr_open(&dev, (uint32_t)dev_index);
451 	if (NULL == dev) {
452 	fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
453 		exit(1);
454 	}
455 
456 #ifndef _WIN32
457 	sigact.sa_handler = sighandler;
458 	sigemptyset(&sigact.sa_mask);
459 	sigact.sa_flags = 0;
460 	sigign.sa_handler = SIG_IGN;
461 	sigaction(SIGINT, &sigact, NULL);
462 	sigaction(SIGTERM, &sigact, NULL);
463 	sigaction(SIGQUIT, &sigact, NULL);
464 	sigaction(SIGPIPE, &sigign, NULL);
465 #else
466 	SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
467 #endif
468 
469 	/* Set the tuner error */
470 	verbose_ppm_set(dev, ppm_error);
471 
472 	/* Set the sample rate */
473 	r = rtlsdr_set_sample_rate(dev, samp_rate);
474 	if (r < 0)
475 		fprintf(stderr, "WARNING: Failed to set sample rate.\n");
476 
477 	/* Set the frequency */
478 	r = rtlsdr_set_center_freq(dev, frequency);
479 	if (r < 0)
480 		fprintf(stderr, "WARNING: Failed to set center freq.\n");
481 	else
482 		fprintf(stderr, "Tuned to %i Hz.\n", frequency);
483 
484 	if (0 == gain) {
485 		 /* Enable automatic gain */
486 		r = rtlsdr_set_tuner_gain_mode(dev, 0);
487 		if (r < 0)
488 			fprintf(stderr, "WARNING: Failed to enable automatic gain.\n");
489 	} else {
490 		/* Enable manual gain */
491 		r = rtlsdr_set_tuner_gain_mode(dev, 1);
492 		if (r < 0)
493 			fprintf(stderr, "WARNING: Failed to enable manual gain.\n");
494 
495 		/* Set the tuner gain */
496 		r = rtlsdr_set_tuner_gain(dev, gain);
497 		if (r < 0)
498 			fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
499 		else
500 			fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0);
501 	}
502 
503 	rtlsdr_set_bias_tee(dev, enable_biastee);
504 	if (enable_biastee)
505 		fprintf(stderr, "activated bias-T on GPIO PIN 0\n");
506 
507 	/* Reset endpoint before we start reading from it (mandatory) */
508 	r = rtlsdr_reset_buffer(dev);
509 	if (r < 0)
510 		fprintf(stderr, "WARNING: Failed to reset buffers.\n");
511 
512 	pthread_mutex_init(&exit_cond_lock, NULL);
513 	pthread_mutex_init(&ll_mutex, NULL);
514 	pthread_mutex_init(&exit_cond_lock, NULL);
515 	pthread_cond_init(&cond, NULL);
516 	pthread_cond_init(&exit_cond, NULL);
517 
518 	memset(&local,0,sizeof(local));
519 	local.sin_family = AF_INET;
520 	local.sin_port = htons(port);
521 	local.sin_addr.s_addr = inet_addr(addr);
522 
523 	listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
524 	r = 1;
525 	setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));
526 	setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
527 	bind(listensocket,(struct sockaddr *)&local,sizeof(local));
528 
529 #ifdef _WIN32
530 	ioctlsocket(listensocket, FIONBIO, &blockmode);
531 #else
532 	r = fcntl(listensocket, F_GETFL, 0);
533 	r = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);
534 #endif
535 
536 	while(1) {
537 		printf("listening...\n");
538 		printf("Use the device argument 'rtl_tcp=%s:%d' in OsmoSDR "
539 		       "(gr-osmosdr) source\n"
540 		       "to receive samples in GRC and control "
541 		       "rtl_tcp parameters (frequency, gain, ...).\n",
542 		       addr, port);
543 		listen(listensocket,1);
544 
545 		while(1) {
546 			FD_ZERO(&readfds);
547 			FD_SET(listensocket, &readfds);
548 			tv.tv_sec = 1;
549 			tv.tv_usec = 0;
550 			r = select(listensocket+1, &readfds, NULL, NULL, &tv);
551 			if(do_exit) {
552 				goto out;
553 			} else if(r) {
554 				rlen = sizeof(remote);
555 				s = accept(listensocket,(struct sockaddr *)&remote, &rlen);
556 				break;
557 			}
558 		}
559 
560 		setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
561 
562 		printf("client accepted!\n");
563 
564 		memset(&dongle_info, 0, sizeof(dongle_info));
565 		memcpy(&dongle_info.magic, "RTL0", 4);
566 
567 		r = rtlsdr_get_tuner_type(dev);
568 		if (r >= 0)
569 			dongle_info.tuner_type = htonl(r);
570 
571 		r = rtlsdr_get_tuner_gains(dev, NULL);
572 		if (r >= 0)
573 			dongle_info.tuner_gain_count = htonl(r);
574 
575 		r = send(s, (const char *)&dongle_info, sizeof(dongle_info), 0);
576 		if (sizeof(dongle_info) != r)
577 			printf("failed to send dongle information\n");
578 
579 		pthread_attr_init(&attr);
580 		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
581 		r = pthread_create(&tcp_worker_thread, &attr, tcp_worker, NULL);
582 		r = pthread_create(&command_thread, &attr, command_worker, NULL);
583 		pthread_attr_destroy(&attr);
584 
585 		r = rtlsdr_read_async(dev, rtlsdr_callback, NULL, buf_num, 0);
586 
587 		pthread_join(tcp_worker_thread, &status);
588 		pthread_join(command_thread, &status);
589 
590 		closesocket(s);
591 
592 		printf("all threads dead..\n");
593 		curelem = ll_buffers;
594 		ll_buffers = 0;
595 
596 		while(curelem != 0) {
597 			prev = curelem;
598 			curelem = curelem->next;
599 			free(prev->data);
600 			free(prev);
601 		}
602 
603 		do_exit = 0;
604 		global_numq = 0;
605 	}
606 
607 out:
608 	rtlsdr_close(dev);
609 	closesocket(listensocket);
610 	closesocket(s);
611 #ifdef _WIN32
612 	WSACleanup();
613 #endif
614 	printf("bye!\n");
615 	return r >= 0 ? r : -r;
616 }
617