parent
6b99aedc4d
commit
d55b491c43
@ -1,2 +1,3 @@ |
|||||||
Steve Markgraf <steve@steve-m.de> |
Steve Markgraf <steve@steve-m.de> |
||||||
Dimitri Stolnikov <horiz0n@gmx.net> |
Dimitri Stolnikov <horiz0n@gmx.net> |
||||||
|
Hoernchen <la@tfc-server.de> |
||||||
|
@ -0,0 +1,474 @@ |
|||||||
|
/*
|
||||||
|
* 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> |
||||||
|
#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]\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[-s samplerate in kHz (default: 2048 kHz)]\n" |
||||||
|
"\toutput filename\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); |
||||||
|
r = select(0+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); |
||||||
|
r = select(0+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; |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
cmd.cmd = 0xff; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char **argv) |
||||||
|
{ |
||||||
|
int r, opt, i; |
||||||
|
char* addr; |
||||||
|
int port = 1234; |
||||||
|
uint32_t frequency = 0, samp_rate = 2048000; |
||||||
|
struct sockaddr_in local, remote; |
||||||
|
int device_count; |
||||||
|
uint32_t dev_index = 0, gain = 5; |
||||||
|
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:s:")) != -1) { |
||||||
|
switch (opt) { |
||||||
|
case 'f': |
||||||
|
frequency = atoi(optarg); |
||||||
|
break; |
||||||
|
case 's': |
||||||
|
samp_rate = atoi(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 %i dB.\n", gain); |
||||||
|
|
||||||
|
/* 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); |
||||||
|
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); |
||||||
|
r = select(0+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; |
||||||
|
} |
Loading…
Reference in new issue