Acurite minor bugfixes
[rtl-433.git] / src / rtl_tcp.c
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 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
44 #ifdef _WIN32
45 #pragma comment(lib, "ws2_32.lib")
46
47 typedef int socklen_t;
48
49 #else
50 #define closesocket close
51 #define SOCKADDR struct sockaddr
52 #define SOCKET int
53 #define SOCKET_ERROR -1
54 #endif
55
56 static SOCKET s;
57
58 static pthread_t tcp_worker_thread;
59 static pthread_t command_thread;
60 static pthread_cond_t exit_cond;
61 static pthread_mutex_t exit_cond_lock;
62 static volatile int dead[2] = {0, 0};
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 int global_numq = 0;
82 static struct llist *ll_buffers = 0;
83
84 static int do_exit = 0;
85
86 void usage(void)
87 {
88         printf("rtl_tcp, an I/Q spectrum server for RTL2832 based DVB-T receivers\n\n"
89                 "Usage:\t[-a listen address]\n"
90                 "\t[-p listen port (default: 1234)]\n"
91                 "\t[-f frequency to tune to [Hz]]\n"
92                 "\t[-g gain (default: 0 for auto)]\n"
93                 "\t[-s samplerate in Hz (default: 2048000 Hz)]\n"
94                 "\t[-b number of buffers (default: 32, set by library)]\n"
95                 "\t[-d device index (default: 0)]\n");
96         exit(1);
97 }
98
99 #ifdef _WIN32
100 int gettimeofday(struct timeval *tv, void* ignored)
101 {
102         FILETIME ft;
103         unsigned __int64 tmp = 0;
104         if (NULL != tv) {
105                 GetSystemTimeAsFileTime(&ft);
106                 tmp |= ft.dwHighDateTime;
107                 tmp <<= 32;
108                 tmp |= ft.dwLowDateTime;
109                 tmp /= 10;
110                 tmp -= 11644473600000000Ui64;
111                 tv->tv_sec = (long)(tmp / 1000000UL);
112                 tv->tv_usec = (long)(tmp % 1000000UL);
113         }
114         return 0;
115 }
116
117 BOOL WINAPI
118 sighandler(int signum)
119 {
120         if (CTRL_C_EVENT == signum) {
121                 fprintf(stderr, "Signal caught, exiting!\n");
122                 do_exit = 1;
123                 rtlsdr_cancel_async(dev);
124                 return TRUE;
125         }
126         return FALSE;
127 }
128 #else
129 static void sighandler(int signum)
130 {
131         fprintf(stderr, "Signal caught, exiting!\n");
132         if (!do_exit) {
133       rtlsdr_cancel_async(dev);
134       do_exit = 1;
135     }
136 }
137 #endif
138
139 void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
140 {
141         if(!do_exit) {
142                 struct llist *rpt = (struct llist*)malloc(sizeof(struct llist));
143                 rpt->data = (char*)malloc(len);
144                 memcpy(rpt->data, buf, len);
145                 rpt->len = len;
146                 rpt->next = NULL;
147
148                 pthread_mutex_lock(&ll_mutex);
149
150                 if (ll_buffers == NULL) {
151                         ll_buffers = rpt;
152                 } else {
153                         struct llist *cur = ll_buffers;
154                         int num_queued = 0;
155
156                         while (cur->next != NULL) {
157                                 cur = cur->next;
158                                 num_queued++;
159                         }
160                         cur->next = rpt;
161
162                         if (num_queued > global_numq)
163                                 printf("ll+, now %d\n", num_queued);
164                         else if (num_queued < global_numq)
165                                 printf("ll-, now %d\n", num_queued);
166
167                         global_numq = num_queued;
168                 }
169                 pthread_cond_signal(&cond);
170                 pthread_mutex_unlock(&ll_mutex);
171         }
172 }
173
174 static void *tcp_worker(void *arg)
175 {
176         struct llist *curelem,*prev;
177         int bytesleft,bytessent, index;
178         struct timeval tv= {1,0};
179         struct timespec ts;
180         struct timeval tp;
181         fd_set writefds;
182         int r = 0;
183
184         while(1) {
185                 if(do_exit)
186                         pthread_exit(0);
187
188                 pthread_mutex_lock(&ll_mutex);
189                 gettimeofday(&tp, NULL);
190                 ts.tv_sec  = tp.tv_sec+5;
191                 ts.tv_nsec = tp.tv_usec * 1000;
192                 r = pthread_cond_timedwait(&cond, &ll_mutex, &ts);
193                 if(r == ETIMEDOUT) {
194                         pthread_mutex_unlock(&ll_mutex);
195                         printf("worker cond timeout\n");
196                         sighandler(0);
197                         dead[0]=1;
198                         pthread_exit(NULL);
199                 }
200
201                 curelem = ll_buffers;
202                 ll_buffers = 0;
203                 pthread_mutex_unlock(&ll_mutex);
204
205                 while(curelem != 0) {
206                         bytesleft = curelem->len;
207                         index = 0;
208                         bytessent = 0;
209                         while(bytesleft > 0) {
210                                 FD_ZERO(&writefds);
211                                 FD_SET(s, &writefds);
212                                 tv.tv_sec = 1;
213                                 tv.tv_usec = 0;
214                                 r = select(s+1, NULL, &writefds, NULL, &tv);
215                                 if(r) {
216                                         bytessent = send(s,  &curelem->data[index], bytesleft, 0);
217                                         if (bytessent == SOCKET_ERROR) {
218                         perror("worker socket error");
219                                                 sighandler(0);
220                                                 dead[0]=1;
221                                                 pthread_exit(NULL);
222                                         } else if (do_exit) {
223                                                 printf("do_exit\n");
224                                                 dead[0]=1;
225                                                 pthread_exit(NULL);
226                                         } else {
227                                                 bytesleft -= bytessent;
228                                                 index += bytessent;
229                                         }
230                                 } else if(do_exit) {
231                                                 printf("worker socket bye\n");
232                                                 sighandler(0);
233                                                 dead[0]=1;
234                                                 pthread_exit(NULL);
235                                 }
236                         }
237                         prev = curelem;
238                         curelem = curelem->next;
239                         free(prev->data);
240                         free(prev);
241                 }
242         }
243 }
244
245 static int set_gain_by_index(rtlsdr_dev_t *_dev, unsigned int index)
246 {
247         int res = 0;
248         int* gains;
249         int count = rtlsdr_get_tuner_gains(_dev, NULL);
250
251         if (count > 0 && (unsigned int)count > index) {
252                 gains = malloc(sizeof(int) * count);
253                 count = rtlsdr_get_tuner_gains(_dev, gains);
254
255                 res = rtlsdr_set_tuner_gain(_dev, gains[index]);
256
257                 free(gains);
258         }
259
260         return res;
261 }
262
263 #ifdef _WIN32
264 #define __attribute__(x)
265 #pragma pack(push, 1)
266 #endif
267 struct command{
268         unsigned char cmd;
269         unsigned int param;
270 }__attribute__((packed));
271 #ifdef _WIN32
272 #pragma pack(pop)
273 #endif
274 static void *command_worker(void *arg)
275 {
276         int left, received;
277         fd_set readfds;
278         struct command cmd={0, 0};
279         struct timeval tv= {1, 0};
280         int r = 0;
281         uint32_t tmp;
282
283         while(1) {
284                 left=sizeof(cmd);
285                 while(left >0) {
286                         FD_ZERO(&readfds);
287                         FD_SET(s, &readfds);
288                         tv.tv_sec = 1;
289                         tv.tv_usec = 0;
290                         r = select(s+1, &readfds, NULL, NULL, &tv);
291                         if(r) {
292                                 received = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0);
293                                 if(received == SOCKET_ERROR){
294                     perror("comm recv socket error");
295                                         sighandler(0);
296                                         dead[1]=1;
297                                         pthread_exit(NULL);
298                                 } else if(do_exit){
299                                         printf("do exit\n");
300                                         dead[1]=1;
301                                         pthread_exit(NULL);
302                                 } else {
303                                         left -= received;
304                                 }
305                         } else if(do_exit) {
306                                 printf("comm recv bye\n");
307                                 sighandler(0);
308                                 dead[1] = 1;
309                                 pthread_exit(NULL);
310                         }
311                 }
312                 switch(cmd.cmd) {
313                 case 0x01:
314                         printf("set freq %d\n", ntohl(cmd.param));
315                         rtlsdr_set_center_freq(dev,ntohl(cmd.param));
316                         break;
317                 case 0x02:
318                         printf("set sample rate %d\n", ntohl(cmd.param));
319                         rtlsdr_set_sample_rate(dev, ntohl(cmd.param));
320                         break;
321                 case 0x03:
322                         printf("set gain mode %d\n", ntohl(cmd.param));
323                         rtlsdr_set_tuner_gain_mode(dev, ntohl(cmd.param));
324                         break;
325                 case 0x04:
326                         printf("set gain %d\n", ntohl(cmd.param));
327                         rtlsdr_set_tuner_gain(dev, ntohl(cmd.param));
328                         break;
329                 case 0x05:
330                         printf("set freq correction %d\n", ntohl(cmd.param));
331                         rtlsdr_set_freq_correction(dev, ntohl(cmd.param));
332                         break;
333                 case 0x06:
334                         tmp = ntohl(cmd.param);
335                         printf("set if stage %d, gain %d\n", tmp >> 16, tmp & 0xffff);
336                         rtlsdr_set_tuner_if_gain(dev, tmp >> 16, tmp & 0xffff);
337                         break;
338                 case 0x07:
339                         printf("set test mode %d\n", ntohl(cmd.param));
340                         rtlsdr_set_testmode(dev, ntohl(cmd.param));
341                         break;
342                 case 0x08:
343                         printf("set agc mode %d\n", ntohl(cmd.param));
344                         rtlsdr_set_agc_mode(dev, ntohl(cmd.param));
345                         break;
346                 case 0x09:
347                         printf("set direct sampling %d\n", ntohl(cmd.param));
348                         rtlsdr_set_direct_sampling(dev, ntohl(cmd.param));
349                         break;
350                 case 0x0a:
351                         printf("set offset tuning %d\n", ntohl(cmd.param));
352                         rtlsdr_set_offset_tuning(dev, ntohl(cmd.param));
353                         break;
354                 case 0x0b:
355                         printf("set rtl xtal %d\n", ntohl(cmd.param));
356                         rtlsdr_set_xtal_freq(dev, ntohl(cmd.param), 0);
357                         break;
358                 case 0x0c:
359                         printf("set tuner xtal %d\n", ntohl(cmd.param));
360                         rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));
361                         break;
362                 case 0x0d:
363                         printf("set tuner gain by index %d\n", ntohl(cmd.param));
364                         set_gain_by_index(dev, ntohl(cmd.param));
365                         break;
366                 default:
367                         break;
368                 }
369                 cmd.cmd = 0xff;
370         }
371 }
372
373 int main(int argc, char **argv)
374 {
375         int r, opt, i;
376         char* addr = "127.0.0.1";
377         int port = 1234;
378         uint32_t frequency = 100000000, samp_rate = 2048000;
379         struct sockaddr_in local, remote;
380         int device_count;
381         uint32_t dev_index = 0, buf_num = 0;
382         int gain = 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:d:")) != -1) {
401                 switch (opt) {
402                 case 'd':
403                         dev_index = atoi(optarg);
404                         break;
405                 case 'f':
406                         frequency = (uint32_t)atof(optarg);
407                         break;
408                 case 'g':
409                         gain = (int)(atof(optarg) * 10); /* tenths of a dB */
410                         break;
411                 case 's':
412                         samp_rate = (uint32_t)atof(optarg);
413                         break;
414                 case 'a':
415                         addr = optarg;
416                         break;
417                 case 'p':
418                         port = atoi(optarg);
419                         break;
420                 case 'b':
421                         buf_num = atoi(optarg);
422                         break;
423                 default:
424                         usage();
425                         break;
426                 }
427         }
428
429         if (argc < optind)
430                 usage();
431
432         device_count = rtlsdr_get_device_count();
433         if (!device_count) {
434                 fprintf(stderr, "No supported devices found.\n");
435                 exit(1);
436         }
437
438         printf("Found %d device(s).\n", device_count);
439
440         rtlsdr_open(&dev, dev_index);
441         if (NULL == dev) {
442         fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
443                 exit(1);
444         }
445
446         printf("Using %s\n", rtlsdr_get_device_name(dev_index));
447 #ifndef _WIN32
448         sigact.sa_handler = sighandler;
449         sigemptyset(&sigact.sa_mask);
450         sigact.sa_flags = 0;
451         sigign.sa_handler = SIG_IGN;
452         sigaction(SIGINT, &sigact, NULL);
453         sigaction(SIGTERM, &sigact, NULL);
454         sigaction(SIGQUIT, &sigact, NULL);
455         sigaction(SIGPIPE, &sigign, NULL);
456 #else
457         SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
458 #endif
459         /* Set the sample rate */
460         r = rtlsdr_set_sample_rate(dev, samp_rate);
461         if (r < 0)
462                 fprintf(stderr, "WARNING: Failed to set sample rate.\n");
463
464         /* Set the frequency */
465         r = rtlsdr_set_center_freq(dev, frequency);
466         if (r < 0)
467                 fprintf(stderr, "WARNING: Failed to set center freq.\n");
468         else
469                 fprintf(stderr, "Tuned to %i Hz.\n", frequency);
470
471         if (0 == gain) {
472                  /* Enable automatic gain */
473                 r = rtlsdr_set_tuner_gain_mode(dev, 0);
474                 if (r < 0)
475                         fprintf(stderr, "WARNING: Failed to enable automatic gain.\n");
476         } else {
477                 /* Enable manual gain */
478                 r = rtlsdr_set_tuner_gain_mode(dev, 1);
479                 if (r < 0)
480                         fprintf(stderr, "WARNING: Failed to enable manual gain.\n");
481
482                 /* Set the tuner gain */
483                 r = rtlsdr_set_tuner_gain(dev, gain);
484                 if (r < 0)
485                         fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
486                 else
487                         fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0);
488         }
489
490         /* Reset endpoint before we start reading from it (mandatory) */
491         r = rtlsdr_reset_buffer(dev);
492         if (r < 0)
493                 fprintf(stderr, "WARNING: Failed to reset buffers.\n");
494
495         pthread_mutex_init(&exit_cond_lock, NULL);
496         pthread_mutex_init(&ll_mutex, NULL);
497         pthread_mutex_init(&exit_cond_lock, NULL);
498         pthread_cond_init(&cond, NULL);
499         pthread_cond_init(&exit_cond, NULL);
500
501         memset(&local,0,sizeof(local));
502         local.sin_family = AF_INET;
503         local.sin_port = htons(port);
504         local.sin_addr.s_addr = inet_addr(addr);
505
506         listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
507         r = 1;
508         setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));
509         setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
510         bind(listensocket,(struct sockaddr *)&local,sizeof(local));
511
512         #ifdef _WIN32
513         ioctlsocket(listensocket, FIONBIO, &blockmode);
514         #else
515         r = fcntl(listensocket, F_GETFL, 0);
516         r = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);
517         #endif
518
519         while(1) {
520                 printf("listening...\n");
521                 printf("Use the device argument 'rtl_tcp=%s:%d' in OsmoSDR "
522                        "(gr-osmosdr) source\n"
523                        "to receive samples in GRC and control "
524                        "rtl_tcp parameters (frequency, gain, ...).\n",
525                        addr, port);
526                 listen(listensocket,1);
527
528                 while(1) {
529                         FD_ZERO(&readfds);
530                         FD_SET(listensocket, &readfds);
531                         tv.tv_sec = 1;
532                         tv.tv_usec = 0;
533                         r = select(listensocket+1, &readfds, NULL, NULL, &tv);
534                         if(do_exit) {
535                                 goto out;
536                         } else if(r) {
537                                 rlen = sizeof(remote);
538                                 s = accept(listensocket,(struct sockaddr *)&remote, &rlen);
539                                 break;
540                         }
541                 }
542
543                 setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
544
545                 printf("client accepted!\n");
546
547                 memset(&dongle_info, 0, sizeof(dongle_info));
548                 memcpy(&dongle_info.magic, "RTL0", 4);
549
550                 r = rtlsdr_get_tuner_type(dev);
551                 if (r >= 0)
552                         dongle_info.tuner_type = htonl(r);
553
554                 r = rtlsdr_get_tuner_gains(dev, NULL);
555                 if (r >= 0)
556                         dongle_info.tuner_gain_count = htonl(r);
557
558                 r = send(s, (const char *)&dongle_info, sizeof(dongle_info), 0);
559                 if (sizeof(dongle_info) != r)
560                         printf("failed to send dongle information\n");
561
562                 pthread_attr_init(&attr);
563                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
564                 r = pthread_create(&tcp_worker_thread, &attr, tcp_worker, NULL);
565                 r = pthread_create(&command_thread, &attr, command_worker, NULL);
566                 pthread_attr_destroy(&attr);
567
568                 r = rtlsdr_read_async(dev, rtlsdr_callback, NULL, buf_num, 0);
569
570                 if(!dead[0])
571                         pthread_join(tcp_worker_thread, &status);
572                 dead[0]=0;
573
574                 if(!dead[1])
575                         pthread_join(command_thread, &status);
576                 dead[1]=0;
577
578                 closesocket(s);
579
580                 printf("all threads dead..\n");
581                 curelem = ll_buffers;
582                 ll_buffers = 0;
583
584                 while(curelem != 0) {
585                         prev = curelem;
586                         curelem = curelem->next;
587                         free(prev->data);
588                         free(prev);
589                 }
590
591                 do_exit = 0;
592                 global_numq = 0;
593         }
594
595 out:
596         rtlsdr_close(dev);
597         closesocket(listensocket);
598         closesocket(s);
599         #ifdef _WIN32
600         WSACleanup();
601         #endif
602         printf("bye!\n");
603         return r >= 0 ? r : -r;
604 }