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