rtl_tcp.c 14 KB

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