123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- /*
- * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
- * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
- * Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
- #include <errno.h>
- #include <signal.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #ifndef _WIN32
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <fcntl.h>
- #else
- #include <WinSock2.h>
- #endif
- #include <pthread.h>
- #include <libusb.h>
- #include "rtl-sdr.h"
- #ifdef _WIN32
- #pragma comment(lib, "ws2_32.lib")
- #else
- #define closesocket close
- #define SOCKADDR struct sockaddr
- #define SOCKET int
- #define SOCKET_ERROR -1
- #endif
- static SOCKET s;
- static pthread_t tcp_worker_thread;
- static pthread_t command_thread;
- static pthread_cond_t exit_cond;
- static pthread_mutex_t exit_cond_lock;
- static volatile int dead[2] = {0, 0};
- static pthread_mutex_t ll_mutex;
- static pthread_cond_t cond;
- struct llist {
- char *data;
- size_t len;
- struct llist *next;
- };
- static rtlsdr_dev_t *dev = NULL;
- int global_numq = 0;
- static struct llist *ll_buffers = 0;
- static int do_exit = 0;
- void usage(void)
- {
- #ifdef _WIN32
- printf("rtl-sdr, an I/Q recorder for RTL2832 based USB-sticks\n\n"
- "Usage:\t rtl-sdr-win.exe [listen addr] [listen port] "
- "[samplerate in kHz] [frequency in Hz] [device index]\n");
- #else
- printf("rtl-sdr, an I/Q recorder for RTL2832 based USB-sticks\n\n"
- "Usage:\t[-a listen address]\n"
- "\t[-p listen port (default: 1234)]\n"
- "\t[-f frequency to tune to [Hz]]\n"
- "\t[-g tuner_gain (default: -1dB)]\n"
- "\t[-s samplerate in Hz (default: 2048000 Hz)]\n"
- "\t[-d device index (default: 0)]\n");
- #endif
- exit(1);
- }
- #ifdef _WIN32
- int gettimeofday(struct timeval *tv, void* ignored)
- {
- FILETIME ft;
- unsigned __int64 tmp = 0;
- if (NULL != tv) {
- GetSystemTimeAsFileTime(&ft);
- tmp |= ft.dwHighDateTime;
- tmp <<= 32;
- tmp |= ft.dwLowDateTime;
- tmp /= 10;
- tmp -= 11644473600000000Ui64;
- tv->tv_sec = (long)(tmp / 1000000UL);
- tv->tv_usec = (long)(tmp % 1000000UL);
- }
- return 0;
- }
- BOOL WINAPI
- sighandler(int signum)
- {
- if (CTRL_C_EVENT == signum) {
- fprintf(stderr, "Signal caught, exiting!\n");
- do_exit = 1;
- rtlsdr_cancel_async(dev);
- return TRUE;
- }
- return FALSE;
- }
- #else
- static void sighandler(int signum)
- {
- fprintf(stderr, "Signal caught, exiting!\n");
- do_exit = 1;
- rtlsdr_cancel_async(dev);
- }
- #endif
- void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
- {
- if(!do_exit) {
- struct llist *rpt = (struct llist*)malloc(sizeof(struct llist));
- rpt->data = (char*)malloc(len);
- memcpy(rpt->data, buf, len);
- rpt->len = len;
- rpt->next = NULL;
- pthread_mutex_lock(&ll_mutex);
- if (ll_buffers == NULL) {
- ll_buffers = rpt;
- } else {
- struct llist *cur = ll_buffers;
- int num_queued = 0;
- while (cur->next != NULL) {
- cur = cur->next;
- num_queued++;
- }
- cur->next = rpt;
- if (num_queued > global_numq)
- printf("ll+, now %d\n", num_queued);
- else if (num_queued < global_numq)
- printf("ll-, now %d\n", num_queued);
- global_numq = num_queued;
- }
- pthread_cond_signal(&cond);
- pthread_mutex_unlock(&ll_mutex);
- }
- }
- static void *tcp_worker(void *arg)
- {
- struct llist *curelem,*prev;
- int bytesleft,bytessent, index;
- struct timeval tv= {1,0};
- struct timespec ts;
- struct timeval tp;
- fd_set writefds;
- int r = 0;
- while(1) {
- if(do_exit)
- pthread_exit(0);
- pthread_mutex_lock(&ll_mutex);
- gettimeofday(&tp, NULL);
- ts.tv_sec = tp.tv_sec+1;
- ts.tv_nsec = tp.tv_usec * 1000;
- r = pthread_cond_timedwait(&cond, &ll_mutex, &ts);
- if(r == ETIMEDOUT) {
- pthread_mutex_unlock(&ll_mutex);
- printf("worker cond timeout\n");
- sighandler(0);
- dead[0]=1;
- pthread_exit(NULL);
- }
- curelem = ll_buffers;
- ll_buffers = 0;
- pthread_mutex_unlock(&ll_mutex);
- while(curelem != 0) {
- bytesleft = curelem->len;
- index = 0;
- bytessent = 0;
- while(bytesleft > 0) {
- FD_ZERO(&writefds);
- FD_SET(s, &writefds);
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- r = select(s+1, NULL, &writefds, NULL, &tv);
- if(r) {
- bytessent = send(s, &curelem->data[index], bytesleft, 0);
- if (bytessent == SOCKET_ERROR || do_exit) {
- printf("worker socket error\n");
- sighandler(0);
- dead[0]=1;
- pthread_exit(NULL);
- } else {
- bytesleft -= bytessent;
- index += bytessent;
- }
- } else if(do_exit) {
- printf("worker socket bye\n");
- sighandler(0);
- dead[0]=1;
- pthread_exit(NULL);
- }
- }
- prev = curelem;
- curelem = curelem->next;
- free(prev->data);
- free(prev);
- }
- }
- }
- #ifdef _WIN32
- #define __attribute__(x)
- #pragma pack(push, 1)
- #endif
- struct command{
- unsigned char cmd;
- unsigned int param;
- }__attribute__((packed));
- #ifdef _WIN32
- #pragma pack(pop)
- #endif
- static void *command_worker(void *arg)
- {
- int left, received;
- fd_set readfds;
- struct command cmd={0, 0};
- struct timeval tv= {1, 0};
- int r =0;
- while(1) {
- left=sizeof(cmd);
- while(left >0) {
- FD_ZERO(&readfds);
- FD_SET(s, &readfds);
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- r = select(s+1, &readfds, NULL, NULL, &tv);
- if(r) {
- received = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0);
- if(received == SOCKET_ERROR || do_exit){
- printf("comm recv socket error\n");
- sighandler(0);
- dead[1]=1;
- pthread_exit(NULL);
- } else {
- left -= received;
- }
- } else if(do_exit) {
- printf("comm recv bye\n");
- sighandler(0);
- dead[1] = 1;
- pthread_exit(NULL);
- }
- }
- switch(cmd.cmd) {
- case 0x01:
- printf("set freq %d\n", cmd.param);
- rtlsdr_set_center_freq(dev, cmd.param);
- break;
- case 0x02:
- printf("set sample rate %d\n", cmd.param);
- rtlsdr_set_sample_rate(dev, cmd.param);
- break;
- case 0x03:
- printf("set gain mode %d\n", cmd.param);
- rtlsdr_set_tuner_gain_mode(dev, cmd.param);
- break;
- case 0x04:
- printf("set gain %d\n", cmd.param);
- rtlsdr_set_tuner_gain(dev, cmd.param);
- break;
- case 0x05:
- printf("set freq correction %d\n", cmd.param);
- rtlsdr_set_freq_correction(dev, cmd.param);
- break;
- default:
- break;
- }
- cmd.cmd = 0xff;
- }
- }
- int main(int argc, char **argv)
- {
- int r, opt, i;
- char* addr = "127.0.0.1";
- int port = 1234;
- uint32_t frequency = 100000000, samp_rate = 2048000;
- struct sockaddr_in local, remote;
- int device_count;
- uint32_t dev_index = 0;
- int gain = -10; // tenths of a dB
- struct llist *curelem,*prev;
- pthread_attr_t attr;
- void *status;
- struct timeval tv = {1,0};
- struct linger ling = {1,0};
- SOCKET listensocket;
- fd_set readfds;
- u_long blockmode = 1;
- #ifdef _WIN32
- WSADATA wsd;
- i = WSAStartup(MAKEWORD(2,2), &wsd);
- #endif
- #ifndef _WIN32
- struct sigaction sigact;
- while ((opt = getopt(argc, argv, "a:p:f:g:s:d:")) != -1) {
- switch (opt) {
- case 'd':
- dev_index = atoi(optarg);
- break;
- case 'f':
- frequency = (uint32_t)atof(optarg);
- break;
- case 'g':
- gain = (int)(atof(optarg) * 10);
- break;
- case 's':
- samp_rate = (uint32_t)atof(optarg);
- break;
- case 'a':
- addr = optarg;
- break;
- case 'p':
- port = atoi(optarg);
- break;
- default:
- usage();
- break;
- }
- }
- if (argc < optind)
- usage();
- #else
- if(argc < 6)
- usage();
- dev_index = atoi(argv[5]);
- frequency = atoi(argv[4]);
- samp_rate = atoi(argv[3])*1000;
- port = atoi(argv[2]);
- addr = argv[1];
- #endif
- printf("listen addr %s:%d\n", addr, port);
- device_count = rtlsdr_get_device_count();
- if (!device_count) {
- fprintf(stderr, "No supported devices found.\n");
- exit(1);
- }
- printf("Found %d device(s).\n", device_count);
- rtlsdr_open(&dev, dev_index);
- if (NULL == dev) {
- fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
- exit(1);
- }
- printf("Using %s\n", rtlsdr_get_device_name(dev_index));
- #ifndef _WIN32
- sigact.sa_handler = sighandler;
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = 0;
- sigaction(SIGINT, &sigact, NULL);
- sigaction(SIGTERM, &sigact, NULL);
- sigaction(SIGQUIT, &sigact, NULL);
- #else
- SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
- #endif
- /* Set the sample rate */
- r = rtlsdr_set_sample_rate(dev, samp_rate);
- if (r < 0)
- fprintf(stderr, "WARNING: Failed to set sample rate.\n");
- /* Set the frequency */
- r = rtlsdr_set_center_freq(dev, frequency);
- if (r < 0)
- fprintf(stderr, "WARNING: Failed to set center freq.\n");
- else
- fprintf(stderr, "Tuned to %i Hz.\n", frequency);
- r = rtlsdr_set_tuner_gain(dev, gain);
- if (r < 0)
- fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
- else
- fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0);
- /* Reset endpoint before we start reading from it (mandatory) */
- r = rtlsdr_reset_buffer(dev);
- if (r < 0)
- fprintf(stderr, "WARNING: Failed to reset buffers.\n");
- pthread_mutex_init(&exit_cond_lock, NULL);
- pthread_mutex_init(&ll_mutex, NULL);
- pthread_mutex_init(&exit_cond_lock, NULL);
- pthread_cond_init(&cond, NULL);
- pthread_cond_init(&exit_cond, NULL);
- memset(&local,0,sizeof(local));
- local.sin_family = AF_INET;
- local.sin_port = htons(port);
- local.sin_addr.s_addr = inet_addr(addr);
- listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- r = 1;
- setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));
- setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
- bind(listensocket,(struct sockaddr *)&local,sizeof(local));
- #ifdef _WIN32
- ioctlsocket(listensocket, FIONBIO, &blockmode);
- #else
- r = fcntl(listensocket, F_GETFL, 0);
- r = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);
- #endif
- while(1) {
- printf("listening...\n");
- listen(listensocket,1);
- while(1) {
- FD_ZERO(&readfds);
- FD_SET(listensocket, &readfds);
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- r = select(listensocket+1, &readfds, NULL, NULL, &tv);
- if(do_exit) {
- goto out;
- } else if(r) {
- r=sizeof(remote);
- s = accept(listensocket,(struct sockaddr *)&remote, &r);
- break;
- }
- }
- setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
- printf("client accepted!\n");
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- r = pthread_create(&tcp_worker_thread, &attr, tcp_worker, NULL);
- r = pthread_create(&command_thread, &attr, command_worker, NULL);
- pthread_attr_destroy(&attr);
- rtlsdr_wait_async(dev, rtlsdr_callback, (void *)0);
- closesocket(s);
- if(!dead[0])
- pthread_join(tcp_worker_thread, &status);
- if(!dead[1])
- pthread_join(command_thread, &status);
- printf("all threads dead..\n");
- curelem = ll_buffers;
- ll_buffers = 0;
- while(curelem != 0) {
- prev = curelem;
- curelem = curelem->next;
- free(prev->data);
- free(prev);
- }
- do_exit = 0;
- global_numq = 0;
- }
- out:
- rtlsdr_close(dev);
- closesocket(listensocket);
- closesocket(s);
- #ifdef _WIN32
- WSACleanup();
- #endif
- printf("bye!\n");
- return r >= 0 ? r : -r;
- }
|