Advertisement
mikikg

rtl_tcp.c

Oct 5th, 2012
1,520
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.36 KB | None | 0 0
  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. static rtlsdr_dev_t *dev = NULL;
  74.  
  75. int global_numq = 0;
  76. static struct llist *ll_buffers = 0;
  77.  
  78. static int do_exit = 0;
  79.  
  80. void usage(void)
  81. {
  82.     printf("rtl_tcp, an I/Q spectrum server for RTL2832 based DVB-T receivers\n\n"
  83.         "Usage:\t[-a listen address]\n"
  84.         "\t[-p listen port (default: 1234)]\n"
  85.         "\t[-f frequency to tune to [Hz]]\n"
  86.         "\t[-g gain (default: 0 for auto)]\n"
  87.         "\t[-s samplerate in Hz (default: 2048000 Hz)]\n"
  88.         "\t[-b number of buffers (default: 32, set by library)]\n"
  89.         "\t[-d device index (default: 0)]\n");
  90.     exit(1);
  91. }
  92.  
  93. #ifdef _WIN32
  94. int gettimeofday(struct timeval *tv, void* ignored)
  95. {
  96.     FILETIME ft;
  97.     unsigned __int64 tmp = 0;
  98.     if (NULL != tv) {
  99.         GetSystemTimeAsFileTime(&ft);
  100.         tmp |= ft.dwHighDateTime;
  101.         tmp <<= 32;
  102.         tmp |= ft.dwLowDateTime;
  103.         tmp /= 10;
  104.         tmp -= 11644473600000000Ui64;
  105.         tv->tv_sec = (long)(tmp / 1000000UL);
  106.         tv->tv_usec = (long)(tmp % 1000000UL);
  107.     }
  108.     return 0;
  109. }
  110.  
  111. BOOL WINAPI
  112. sighandler(int signum)
  113. {
  114.     if (CTRL_C_EVENT == signum) {
  115.         fprintf(stderr, "Signal caught, exiting!\n");
  116.         do_exit = 1;
  117.         rtlsdr_cancel_async(dev);
  118.         return TRUE;
  119.     }
  120.     return FALSE;
  121. }
  122. #else
  123. static void sighandler(int signum)
  124. {
  125.     fprintf(stderr, "Signal caught, exiting!\n");
  126.     do_exit = 1;
  127.     rtlsdr_cancel_async(dev);
  128. }
  129. #endif
  130.  
  131. void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
  132. {
  133.     if(!do_exit) {
  134.         struct llist *rpt = (struct llist*)malloc(sizeof(struct llist));
  135.         rpt->data = (char*)malloc(len);
  136.         memcpy(rpt->data, buf, len);
  137.         rpt->len = len;
  138.         rpt->next = NULL;
  139.  
  140.         pthread_mutex_lock(&ll_mutex);
  141.  
  142.         if (ll_buffers == NULL) {
  143.             ll_buffers = rpt;
  144.         } else {
  145.             struct llist *cur = ll_buffers;
  146.             int num_queued = 0;
  147.  
  148.             while (cur->next != NULL) {
  149.                 cur = cur->next;
  150.                 num_queued++;
  151.             }
  152.             cur->next = rpt;
  153.  
  154.             if (num_queued > global_numq)
  155.                 printf("ll+, now %d\n", num_queued);
  156.             else if (num_queued < global_numq)
  157.                 printf("ll-, now %d\n", num_queued);
  158.  
  159.             global_numq = num_queued;
  160.         }
  161.         pthread_cond_signal(&cond);
  162.         pthread_mutex_unlock(&ll_mutex);
  163.     }
  164. }
  165.  
  166. static void *tcp_worker(void *arg)
  167. {
  168.     struct llist *curelem,*prev;
  169.     int bytesleft,bytessent, index;
  170.     struct timeval tv= {1,0};
  171.     struct timespec ts;
  172.     struct timeval tp;
  173.     fd_set writefds;
  174.     int r = 0;
  175.  
  176.     while(1) {
  177.         if(do_exit)
  178.             pthread_exit(0);
  179.  
  180.         pthread_mutex_lock(&ll_mutex);
  181.         gettimeofday(&tp, NULL);
  182.         ts.tv_sec  = tp.tv_sec+1;
  183.         ts.tv_nsec = tp.tv_usec * 1000;
  184.         r = pthread_cond_timedwait(&cond, &ll_mutex, &ts);
  185.         if(r == ETIMEDOUT) {
  186.             pthread_mutex_unlock(&ll_mutex);
  187.             printf("worker cond timeout\n");
  188.             sighandler(0);
  189.             dead[0]=1;
  190.             pthread_exit(NULL);
  191.         }
  192.  
  193.         curelem = ll_buffers;
  194.         ll_buffers = 0;
  195.         pthread_mutex_unlock(&ll_mutex);
  196.  
  197.         while(curelem != 0) {
  198.             bytesleft = curelem->len;
  199.             index = 0;
  200.             bytessent = 0;
  201.             while(bytesleft > 0) {
  202.                 FD_ZERO(&writefds);
  203.                 FD_SET(s, &writefds);
  204.                 tv.tv_sec = 1;
  205.                 tv.tv_usec = 0;
  206.                 r = select(s+1, NULL, &writefds, NULL, &tv);
  207.                 if(r) {
  208.                     bytessent = send(s,  &curelem->data[index], bytesleft, 0);
  209.                     if (bytessent == SOCKET_ERROR || do_exit) {
  210.                         printf("worker socket error\n");
  211.                         sighandler(0);
  212.                         dead[0]=1;
  213.                         pthread_exit(NULL);
  214.                     } else {
  215.                         bytesleft -= bytessent;
  216.                         index += bytessent;
  217.                     }
  218.                 } else if(do_exit) {
  219.                         printf("worker socket bye\n");
  220.                         sighandler(0);
  221.                         dead[0]=1;
  222.                         pthread_exit(NULL);
  223.                 }
  224.             }
  225.             prev = curelem;
  226.             curelem = curelem->next;
  227.             free(prev->data);
  228.             free(prev);
  229.         }
  230.     }
  231. }
  232.  
  233. #ifdef _WIN32
  234. #define __attribute__(x)
  235. #pragma pack(push, 1)
  236. #endif
  237. struct command{
  238.     unsigned char cmd;
  239.     unsigned int param;
  240. }__attribute__((packed));
  241. #ifdef _WIN32
  242. #pragma pack(pop)
  243. #endif
  244. static void *command_worker(void *arg)
  245. {
  246.     int left, received;
  247.     fd_set readfds;
  248.     struct command cmd={0, 0};
  249.     struct timeval tv= {1, 0};
  250.     int r =0;
  251.     while(1) {
  252.         left=sizeof(cmd);
  253.         while(left >0) {
  254.             FD_ZERO(&readfds);
  255.             FD_SET(s, &readfds);
  256.             tv.tv_sec = 1;
  257.             tv.tv_usec = 0;
  258.             r = select(s+1, &readfds, NULL, NULL, &tv);
  259.             if(r) {
  260.                 received = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0);
  261.                 if(received == SOCKET_ERROR || do_exit){
  262.                     printf("comm recv socket error\n");
  263.                     sighandler(0);
  264.                     dead[1]=1;
  265.                     pthread_exit(NULL);
  266.                 } else {
  267.                     left -= received;
  268.                 }
  269.             } else if(do_exit) {
  270.                 printf("comm recv bye\n");
  271.                 sighandler(0);
  272.                 dead[1] = 1;
  273.                 pthread_exit(NULL);
  274.             }
  275.         }
  276.         switch(cmd.cmd) {
  277.         case 0x01:
  278.             printf("set freq %d\n", ntohl(cmd.param));
  279.             rtlsdr_set_center_freq(dev,ntohl(cmd.param));
  280.             break;
  281.         case 0x02:
  282.             printf("set sample rate %d\n", ntohl(cmd.param));
  283.             rtlsdr_set_sample_rate(dev, ntohl(cmd.param));
  284.             break;
  285.         case 0x03:
  286.             printf("set gain mode %d\n", ntohl(cmd.param));
  287.             rtlsdr_set_tuner_gain_mode(dev, ntohl(cmd.param));
  288.             break;
  289.         case 0x04:
  290.             printf("set gain %d\n", ntohl(cmd.param));
  291.             rtlsdr_set_tuner_gain(dev, ntohl(cmd.param));
  292.             break;
  293.         case 0x05:
  294.             printf("set freq correction %d\n", ntohl(cmd.param));
  295.             rtlsdr_set_freq_correction(dev, ntohl(cmd.param));
  296.             break;
  297.         default:
  298.             break;
  299.         }
  300.         cmd.cmd = 0xff;
  301.     }
  302. }
  303.  
  304. int main(int argc, char **argv)
  305. {
  306.     int r, opt, i;
  307.     char* addr = "127.0.0.1";
  308.     int port = 1234;
  309.     uint32_t frequency = 100000000, samp_rate = 2048000;
  310.     struct sockaddr_in local, remote;
  311.     int device_count;
  312.     uint32_t dev_index = 0, buf_num = 0;
  313.     int gain = 0;
  314.     struct llist *curelem,*prev;
  315.     pthread_attr_t attr;
  316.     void *status;
  317.     struct timeval tv = {1,0};
  318.     struct linger ling = {1,0};
  319.     SOCKET listensocket;
  320.     socklen_t rlen;
  321.     fd_set readfds;
  322.     u_long blockmode = 1;
  323. #ifdef _WIN32
  324.     WSADATA wsd;
  325.     i = WSAStartup(MAKEWORD(2,2), &wsd);
  326. #else
  327.     struct sigaction sigact, sigign;
  328. #endif
  329.  
  330.     while ((opt = getopt(argc, argv, "a:p:f:g:s:b:d:")) != -1) {
  331.         switch (opt) {
  332.         case 'd':
  333.             dev_index = atoi(optarg);
  334.             break;
  335.         case 'f':
  336.             frequency = (uint32_t)atof(optarg);
  337.             break;
  338.         case 'g':
  339.             gain = (int)(atof(optarg) * 10); /* tenths of a dB */
  340.             break;
  341.         case 's':
  342.             samp_rate = (uint32_t)atof(optarg);
  343.             break;
  344.         case 'a':
  345.             addr = optarg;
  346.             break;
  347.         case 'p':
  348.             port = atoi(optarg);
  349.             break;
  350.         case 'b':
  351.             buf_num = atoi(optarg);
  352.             break;
  353.         default:
  354.             usage();
  355.             break;
  356.         }
  357.     }
  358.  
  359.     if (argc < optind)
  360.         usage();
  361.  
  362.     device_count = rtlsdr_get_device_count();
  363.     if (!device_count) {
  364.         fprintf(stderr, "No supported devices found.\n");
  365.         exit(1);
  366.     }
  367.  
  368.     printf("Found %d device(s).\n", device_count);
  369.  
  370.     rtlsdr_open(&dev, dev_index);
  371.     if (NULL == dev) {
  372.     fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
  373.         exit(1);
  374.     }
  375.  
  376.     printf("Using %s\n", rtlsdr_get_device_name(dev_index));
  377. #ifndef _WIN32
  378.     sigact.sa_handler = sighandler;
  379.     sigemptyset(&sigact.sa_mask);
  380.     sigact.sa_flags = 0;
  381.     sigign.sa_handler = SIG_IGN;
  382.     sigaction(SIGINT, &sigact, NULL);
  383.     sigaction(SIGTERM, &sigact, NULL);
  384.     sigaction(SIGQUIT, &sigact, NULL);
  385.     sigaction(SIGPIPE, &sigign, NULL);
  386. #else
  387.     SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
  388. #endif
  389.     /* Set the sample rate */
  390.     r = rtlsdr_set_sample_rate(dev, samp_rate);
  391.     if (r < 0)
  392.         fprintf(stderr, "WARNING: Failed to set sample rate.\n");
  393.  
  394.     /****** FORCE direct-sampling mode ******/
  395.     rtlsdr_set_direct_sampling(dev,1);
  396.  
  397.     /* Set the frequency */
  398.     r = rtlsdr_set_center_freq(dev, frequency);
  399.     if (r < 0)
  400.         fprintf(stderr, "WARNING: Failed to set center freq.\n");
  401.     else
  402.         fprintf(stderr, "Tuned to %i Hz.\n", frequency);
  403.  
  404.     if (0 == gain) {
  405.          /* Enable automatic gain */
  406.         r = rtlsdr_set_tuner_gain_mode(dev, 0);
  407.         if (r < 0)
  408.             fprintf(stderr, "WARNING: Failed to enable automatic gain.\n");
  409.     } else {
  410.         /* Enable manual gain */
  411.         r = rtlsdr_set_tuner_gain_mode(dev, 1);
  412.         if (r < 0)
  413.             fprintf(stderr, "WARNING: Failed to enable manual gain.\n");
  414.  
  415.         /* Set the tuner gain */
  416.         r = rtlsdr_set_tuner_gain(dev, gain);
  417.         if (r < 0)
  418.             fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
  419.         else
  420.             fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0);
  421.     }
  422.  
  423.     /* Reset endpoint before we start reading from it (mandatory) */
  424.     r = rtlsdr_reset_buffer(dev);
  425.     if (r < 0)
  426.         fprintf(stderr, "WARNING: Failed to reset buffers.\n");
  427.  
  428.     pthread_mutex_init(&exit_cond_lock, NULL);
  429.     pthread_mutex_init(&ll_mutex, NULL);
  430.     pthread_mutex_init(&exit_cond_lock, NULL);
  431.     pthread_cond_init(&cond, NULL);
  432.     pthread_cond_init(&exit_cond, NULL);
  433.  
  434.     memset(&local,0,sizeof(local));
  435.     local.sin_family = AF_INET;
  436.     local.sin_port = htons(port);
  437.     local.sin_addr.s_addr = inet_addr(addr);
  438.  
  439.     listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  440.     r = 1;
  441.     setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));
  442.     setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
  443.     bind(listensocket,(struct sockaddr *)&local,sizeof(local));
  444.  
  445.     #ifdef _WIN32
  446.     ioctlsocket(listensocket, FIONBIO, &blockmode);
  447.     #else
  448.     r = fcntl(listensocket, F_GETFL, 0);
  449.     r = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);
  450.     #endif
  451.  
  452.     while(1) {
  453.         printf("listening...\n");
  454.         printf("Use the device argument 'rtl_tcp=%s:%d' in OsmoSDR "
  455.                "(gr-osmosdr) source\n"
  456.                "to receive samples in GRC and control "
  457.                "rtl_tcp parameters (frequency, gain, ...).\n",
  458.                addr, port);
  459.         listen(listensocket,1);
  460.  
  461.         while(1) {
  462.             FD_ZERO(&readfds);
  463.             FD_SET(listensocket, &readfds);
  464.             tv.tv_sec = 1;
  465.             tv.tv_usec = 0;
  466.             r = select(listensocket+1, &readfds, NULL, NULL, &tv);
  467.             if(do_exit) {
  468.                 goto out;
  469.             } else if(r) {
  470.                 rlen = sizeof(remote);
  471.                 s = accept(listensocket,(struct sockaddr *)&remote, &rlen);
  472.                 break;
  473.             }
  474.         }
  475.  
  476.         setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
  477.  
  478.         printf("client accepted!\n");
  479.  
  480.         pthread_attr_init(&attr);
  481.         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  482.         r = pthread_create(&tcp_worker_thread, &attr, tcp_worker, NULL);
  483.         r = pthread_create(&command_thread, &attr, command_worker, NULL);
  484.         pthread_attr_destroy(&attr);
  485.  
  486.         r = rtlsdr_read_async(dev, rtlsdr_callback, (void *)0,
  487.                       buf_num, 0);
  488.  
  489.         closesocket(s);
  490.         if(!dead[0])
  491.             pthread_join(tcp_worker_thread, &status);
  492.  
  493.         if(!dead[1])
  494.             pthread_join(command_thread, &status);
  495.  
  496.         printf("all threads dead..\n");
  497.         curelem = ll_buffers;
  498.         ll_buffers = 0;
  499.  
  500.         while(curelem != 0) {
  501.             prev = curelem;
  502.             curelem = curelem->next;
  503.             free(prev->data);
  504.             free(prev);
  505.         }
  506.  
  507.         do_exit = 0;
  508.         global_numq = 0;
  509.     }
  510.  
  511. out:
  512.     rtlsdr_close(dev);
  513.     closesocket(listensocket);
  514.     closesocket(s);
  515.     #ifdef _WIN32
  516.     WSACleanup();
  517.     #endif
  518.     printf("bye!\n");
  519.     return r >= 0 ? r : -r;
  520. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement