mikikg

rtl_tcp.c

Oct 5th, 2012
1,292
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×