/host/hackrf-tools/src/hackrf_transfer.c

https://github.com/antrorsum/hackrf · C · 956 lines · 787 code · 128 blank · 41 comment · 173 complexity · 01b21e2c6aec2a21d86baf7d6fe118ed MD5 · raw file

  1. /*
  2. * Copyright 2012 Jared Boone <jared@sharebrained.com>
  3. * Copyright 2013-2014 Benjamin Vernoux <titanmkd@gmail.com>
  4. *
  5. * This file is part of HackRF.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2, or (at your option)
  10. * any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; see the file COPYING. If not, write to
  19. * the Free Software Foundation, Inc., 51 Franklin Street,
  20. * Boston, MA 02110-1301, USA.
  21. */
  22. #include <hackrf.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <getopt.h>
  27. #include <time.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <fcntl.h>
  31. #include <errno.h>
  32. #ifndef bool
  33. typedef int bool;
  34. #define true 1
  35. #define false 0
  36. #endif
  37. #ifdef _WIN32
  38. #include <windows.h>
  39. #ifdef _MSC_VER
  40. #ifdef _WIN64
  41. typedef int64_t ssize_t;
  42. #else
  43. typedef int32_t ssize_t;
  44. #endif
  45. #define strtoull _strtoui64
  46. #define snprintf _snprintf
  47. int gettimeofday(struct timeval *tv, void* ignored)
  48. {
  49. FILETIME ft;
  50. unsigned __int64 tmp = 0;
  51. if (NULL != tv) {
  52. GetSystemTimeAsFileTime(&ft);
  53. tmp |= ft.dwHighDateTime;
  54. tmp <<= 32;
  55. tmp |= ft.dwLowDateTime;
  56. tmp /= 10;
  57. tmp -= 11644473600000000Ui64;
  58. tv->tv_sec = (long)(tmp / 1000000UL);
  59. tv->tv_usec = (long)(tmp % 1000000UL);
  60. }
  61. return 0;
  62. }
  63. #endif
  64. #endif
  65. #if defined(__GNUC__)
  66. #include <unistd.h>
  67. #include <sys/time.h>
  68. #endif
  69. #include <signal.h>
  70. #define FD_BUFFER_SIZE (8*1024)
  71. #define FREQ_ONE_MHZ (1000000ull)
  72. #define DEFAULT_FREQ_HZ (900000000ull) /* 900MHz */
  73. #define FREQ_MIN_HZ (0ull) /* 0 Hz */
  74. #define FREQ_MAX_HZ (7250000000ull) /* 7250MHz */
  75. #define IF_MIN_HZ (2150000000ull)
  76. #define IF_MAX_HZ (2750000000ull)
  77. #define LO_MIN_HZ (84375000ull)
  78. #define LO_MAX_HZ (5400000000ull)
  79. #define DEFAULT_LO_HZ (1000000000ull)
  80. #define DEFAULT_SAMPLE_RATE_HZ (10000000) /* 10MHz default sample rate */
  81. #define DEFAULT_BASEBAND_FILTER_BANDWIDTH (5000000) /* 5MHz default */
  82. #define SAMPLES_TO_XFER_MAX (0x8000000000000000ull) /* Max value */
  83. #define BASEBAND_FILTER_BW_MIN (1750000) /* 1.75 MHz min value */
  84. #define BASEBAND_FILTER_BW_MAX (28000000) /* 28 MHz max value */
  85. #if defined _WIN32
  86. #define sleep(a) Sleep( (a*1000) )
  87. #endif
  88. /* WAVE or RIFF WAVE file format containing IQ 2x8bits data for HackRF compatible with SDR# Wav IQ file */
  89. typedef struct
  90. {
  91. char groupID[4]; /* 'RIFF' */
  92. uint32_t size; /* File size + 8bytes */
  93. char riffType[4]; /* 'WAVE'*/
  94. } t_WAVRIFF_hdr;
  95. #define FormatID "fmt " /* chunkID for Format Chunk. NOTE: There is a space at the end of this ID. */
  96. typedef struct {
  97. char chunkID[4]; /* 'fmt ' */
  98. uint32_t chunkSize; /* 16 fixed */
  99. uint16_t wFormatTag; /* 1 fixed */
  100. uint16_t wChannels; /* 2 fixed */
  101. uint32_t dwSamplesPerSec; /* Freq Hz sampling */
  102. uint32_t dwAvgBytesPerSec; /* Freq Hz sampling x 2 */
  103. uint16_t wBlockAlign; /* 2 fixed */
  104. uint16_t wBitsPerSample; /* 8 fixed */
  105. } t_FormatChunk;
  106. typedef struct
  107. {
  108. char chunkID[4]; /* 'data' */
  109. uint32_t chunkSize; /* Size of data in bytes */
  110. /* Samples I(8bits) then Q(8bits), I, Q ... */
  111. } t_DataChunk;
  112. typedef struct
  113. {
  114. t_WAVRIFF_hdr hdr;
  115. t_FormatChunk fmt_chunk;
  116. t_DataChunk data_chunk;
  117. } t_wav_file_hdr;
  118. t_wav_file_hdr wave_file_hdr =
  119. {
  120. /* t_WAVRIFF_hdr */
  121. {
  122. { 'R', 'I', 'F', 'F' }, /* groupID */
  123. 0, /* size to update later */
  124. { 'W', 'A', 'V', 'E' }
  125. },
  126. /* t_FormatChunk */
  127. {
  128. { 'f', 'm', 't', ' ' }, /* char chunkID[4]; */
  129. 16, /* uint32_t chunkSize; */
  130. 1, /* uint16_t wFormatTag; 1 fixed */
  131. 2, /* uint16_t wChannels; 2 fixed */
  132. 0, /* uint32_t dwSamplesPerSec; Freq Hz sampling to update later */
  133. 0, /* uint32_t dwAvgBytesPerSec; Freq Hz sampling x 2 to update later */
  134. 2, /* uint16_t wBlockAlign; 2 fixed */
  135. 8, /* uint16_t wBitsPerSample; 8 fixed */
  136. },
  137. /* t_DataChunk */
  138. {
  139. { 'd', 'a', 't', 'a' }, /* char chunkID[4]; */
  140. 0, /* uint32_t chunkSize; to update later */
  141. }
  142. };
  143. typedef enum {
  144. TRANSCEIVER_MODE_OFF = 0,
  145. TRANSCEIVER_MODE_RX = 1,
  146. TRANSCEIVER_MODE_TX = 2
  147. } transceiver_mode_t;
  148. static transceiver_mode_t transceiver_mode = TRANSCEIVER_MODE_RX;
  149. #define U64TOA_MAX_DIGIT (31)
  150. typedef struct
  151. {
  152. char data[U64TOA_MAX_DIGIT+1];
  153. } t_u64toa;
  154. t_u64toa ascii_u64_data1;
  155. t_u64toa ascii_u64_data2;
  156. static float
  157. TimevalDiff(const struct timeval *a, const struct timeval *b)
  158. {
  159. return (a->tv_sec - b->tv_sec) + 1e-6f * (a->tv_usec - b->tv_usec);
  160. }
  161. int parse_u64(char* s, uint64_t* const value) {
  162. uint_fast8_t base = 10;
  163. char* s_end;
  164. uint64_t u64_value;
  165. if( strlen(s) > 2 ) {
  166. if( s[0] == '0' ) {
  167. if( (s[1] == 'x') || (s[1] == 'X') ) {
  168. base = 16;
  169. s += 2;
  170. } else if( (s[1] == 'b') || (s[1] == 'B') ) {
  171. base = 2;
  172. s += 2;
  173. }
  174. }
  175. }
  176. s_end = s;
  177. u64_value = strtoull(s, &s_end, base);
  178. if( (s != s_end) && (*s_end == 0) ) {
  179. *value = u64_value;
  180. return HACKRF_SUCCESS;
  181. } else {
  182. return HACKRF_ERROR_INVALID_PARAM;
  183. }
  184. }
  185. int parse_u32(char* s, uint32_t* const value) {
  186. uint_fast8_t base = 10;
  187. char* s_end;
  188. uint64_t ulong_value;
  189. if( strlen(s) > 2 ) {
  190. if( s[0] == '0' ) {
  191. if( (s[1] == 'x') || (s[1] == 'X') ) {
  192. base = 16;
  193. s += 2;
  194. } else if( (s[1] == 'b') || (s[1] == 'B') ) {
  195. base = 2;
  196. s += 2;
  197. }
  198. }
  199. }
  200. s_end = s;
  201. ulong_value = strtoul(s, &s_end, base);
  202. if( (s != s_end) && (*s_end == 0) ) {
  203. *value = (uint32_t)ulong_value;
  204. return HACKRF_SUCCESS;
  205. } else {
  206. return HACKRF_ERROR_INVALID_PARAM;
  207. }
  208. }
  209. static char *stringrev(char *str)
  210. {
  211. char *p1, *p2;
  212. if(! str || ! *str)
  213. return str;
  214. for(p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
  215. {
  216. *p1 ^= *p2;
  217. *p2 ^= *p1;
  218. *p1 ^= *p2;
  219. }
  220. return str;
  221. }
  222. char* u64toa(uint64_t val, t_u64toa* str)
  223. {
  224. #define BASE (10ull) /* Base10 by default */
  225. uint64_t sum;
  226. int pos;
  227. int digit;
  228. int max_len;
  229. char* res;
  230. sum = val;
  231. max_len = U64TOA_MAX_DIGIT;
  232. pos = 0;
  233. do
  234. {
  235. digit = (sum % BASE);
  236. str->data[pos] = digit + '0';
  237. pos++;
  238. sum /= BASE;
  239. }while( (sum>0) && (pos < max_len) );
  240. if( (pos == max_len) && (sum>0) )
  241. return NULL;
  242. str->data[pos] = '\0';
  243. res = stringrev(str->data);
  244. return res;
  245. }
  246. volatile bool do_exit = false;
  247. FILE* fd = NULL;
  248. volatile uint32_t byte_count = 0;
  249. bool receive = false;
  250. bool receive_wav = false;
  251. bool transmit = false;
  252. struct timeval time_start;
  253. struct timeval t_start;
  254. bool automatic_tuning = false;
  255. uint64_t freq_hz;
  256. bool if_freq = false;
  257. uint64_t if_freq_hz;
  258. bool lo_freq = false;
  259. uint64_t lo_freq_hz = DEFAULT_LO_HZ;
  260. bool image_reject = false;
  261. uint32_t image_reject_selection;
  262. bool amp = false;
  263. uint32_t amp_enable;
  264. bool antenna = false;
  265. uint32_t antenna_enable;
  266. bool sample_rate = false;
  267. uint32_t sample_rate_hz;
  268. bool limit_num_samples = false;
  269. uint64_t samples_to_xfer = 0;
  270. size_t bytes_to_xfer = 0;
  271. bool baseband_filter_bw = false;
  272. uint32_t baseband_filter_bw_hz = 0;
  273. int rx_callback(hackrf_transfer* transfer) {
  274. size_t bytes_to_write;
  275. int i;
  276. if( fd != NULL )
  277. {
  278. ssize_t bytes_written;
  279. byte_count += transfer->valid_length;
  280. bytes_to_write = transfer->valid_length;
  281. if (limit_num_samples) {
  282. if (bytes_to_write >= bytes_to_xfer) {
  283. bytes_to_write = bytes_to_xfer;
  284. }
  285. bytes_to_xfer -= bytes_to_write;
  286. }
  287. if (receive_wav) {
  288. /* convert .wav contents from signed to unsigned */
  289. for (i = 0; i < bytes_to_write; i++) {
  290. transfer->buffer[i] ^= (uint8_t)0x80;
  291. }
  292. }
  293. bytes_written = fwrite(transfer->buffer, 1, bytes_to_write, fd);
  294. if ((bytes_written != bytes_to_write)
  295. || (limit_num_samples && (bytes_to_xfer == 0))) {
  296. return -1;
  297. } else {
  298. return 0;
  299. }
  300. } else {
  301. return -1;
  302. }
  303. }
  304. int tx_callback(hackrf_transfer* transfer) {
  305. size_t bytes_to_read;
  306. if( fd != NULL )
  307. {
  308. ssize_t bytes_read;
  309. byte_count += transfer->valid_length;
  310. bytes_to_read = transfer->valid_length;
  311. if (limit_num_samples) {
  312. if (bytes_to_read >= bytes_to_xfer) {
  313. /*
  314. * In this condition, we probably tx some of the previous
  315. * buffer contents at the end. :-(
  316. */
  317. bytes_to_read = bytes_to_xfer;
  318. }
  319. bytes_to_xfer -= bytes_to_read;
  320. }
  321. bytes_read = fread(transfer->buffer, 1, bytes_to_read, fd);
  322. if ((bytes_read != bytes_to_read)
  323. || (limit_num_samples && (bytes_to_xfer == 0))) {
  324. return -1;
  325. } else {
  326. return 0;
  327. }
  328. } else {
  329. return -1;
  330. }
  331. }
  332. static void usage() {
  333. printf("Usage:\n");
  334. printf("\t-r <filename> # Receive data into file.\n");
  335. printf("\t-t <filename> # Transmit data from file.\n");
  336. printf("\t-w # Receive data into file with WAV header and automatic name.\n");
  337. printf("\t # This is for SDR# compatibility and may not work with other software.\n");
  338. printf("\t[-f freq_hz] # Frequency in Hz [%sMHz to %sMHz].\n",
  339. u64toa((FREQ_MIN_HZ/FREQ_ONE_MHZ),&ascii_u64_data1),
  340. u64toa((FREQ_MAX_HZ/FREQ_ONE_MHZ),&ascii_u64_data2));
  341. printf("\t[-i if_freq_hz] # Intermediate Frequency (IF) in Hz [%sMHz to %sMHz].\n",
  342. u64toa((IF_MIN_HZ/FREQ_ONE_MHZ),&ascii_u64_data1),
  343. u64toa((IF_MAX_HZ/FREQ_ONE_MHZ),&ascii_u64_data2));
  344. printf("\t[-o lo_freq_hz] # Front-end Local Oscillator (LO) frequency in Hz [%sMHz to %sMHz].\n",
  345. u64toa((LO_MIN_HZ/FREQ_ONE_MHZ),&ascii_u64_data1),
  346. u64toa((LO_MAX_HZ/FREQ_ONE_MHZ),&ascii_u64_data2));
  347. printf("\t[-m image_reject] # Image rejection filter selection, 0=bypass, 1=low pass, 2=high pass.\n");
  348. printf("\t[-a amp_enable] # RX/TX RF amplifier 1=Enable, 0=Disable.\n");
  349. printf("\t[-p antenna_enable] # Antenna port power, 1=Enable, 0=Disable.\n");
  350. printf("\t[-l gain_db] # RX LNA (IF) gain, 0-40dB, 8dB steps\n");
  351. printf("\t[-g gain_db] # RX VGA (baseband) gain, 0-62dB, 2dB steps\n");
  352. printf("\t[-x gain_db] # TX VGA (IF) gain, 0-47dB, 1dB steps\n");
  353. printf("\t[-s sample_rate_hz] # Sample rate in Hz (8/10/12.5/16/20MHz, default %sMHz).\n",
  354. u64toa((DEFAULT_SAMPLE_RATE_HZ/FREQ_ONE_MHZ),&ascii_u64_data1));
  355. printf("\t[-n num_samples] # Number of samples to transfer (default is unlimited).\n");
  356. printf("\t[-b baseband_filter_bw_hz] # Set baseband filter bandwidth in MHz.\n\tPossible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz, default < sample_rate_hz.\n" );
  357. }
  358. static hackrf_device* device = NULL;
  359. #ifdef _MSC_VER
  360. BOOL WINAPI
  361. sighandler(int signum)
  362. {
  363. if (CTRL_C_EVENT == signum) {
  364. fprintf(stdout, "Caught signal %d\n", signum);
  365. do_exit = true;
  366. return TRUE;
  367. }
  368. return FALSE;
  369. }
  370. #else
  371. void sigint_callback_handler(int signum)
  372. {
  373. fprintf(stdout, "Caught signal %d\n", signum);
  374. do_exit = true;
  375. }
  376. #endif
  377. #define PATH_FILE_MAX_LEN (FILENAME_MAX)
  378. #define DATE_TIME_MAX_LEN (32)
  379. int main(int argc, char** argv) {
  380. int opt;
  381. char path_file[PATH_FILE_MAX_LEN];
  382. char date_time[DATE_TIME_MAX_LEN];
  383. const char* path = NULL;
  384. int result;
  385. time_t rawtime;
  386. struct tm * timeinfo;
  387. long int file_pos;
  388. int exit_code = EXIT_SUCCESS;
  389. struct timeval t_end;
  390. float time_diff;
  391. unsigned int lna_gain=8, vga_gain=20, txvga_gain=0;
  392. while( (opt = getopt(argc, argv, "wr:t:f:i:o:m:a:p:s:n:b:l:g:x:")) != EOF )
  393. {
  394. result = HACKRF_SUCCESS;
  395. switch( opt )
  396. {
  397. case 'w':
  398. receive_wav = true;
  399. break;
  400. case 'r':
  401. receive = true;
  402. path = optarg;
  403. break;
  404. case 't':
  405. transmit = true;
  406. path = optarg;
  407. break;
  408. case 'f':
  409. automatic_tuning = true;
  410. result = parse_u64(optarg, &freq_hz);
  411. break;
  412. case 'i':
  413. if_freq = true;
  414. result = parse_u64(optarg, &if_freq_hz);
  415. break;
  416. case 'o':
  417. lo_freq = true;
  418. result = parse_u64(optarg, &lo_freq_hz);
  419. break;
  420. case 'm':
  421. image_reject = true;
  422. result = parse_u32(optarg, &image_reject_selection);
  423. break;
  424. case 'a':
  425. amp = true;
  426. result = parse_u32(optarg, &amp_enable);
  427. break;
  428. case 'p':
  429. antenna = true;
  430. result = parse_u32(optarg, &antenna_enable);
  431. break;
  432. case 'l':
  433. result = parse_u32(optarg, &lna_gain);
  434. break;
  435. case 'g':
  436. result = parse_u32(optarg, &vga_gain);
  437. break;
  438. case 'x':
  439. result = parse_u32(optarg, &txvga_gain);
  440. break;
  441. case 's':
  442. sample_rate = true;
  443. result = parse_u32(optarg, &sample_rate_hz);
  444. break;
  445. case 'n':
  446. limit_num_samples = true;
  447. result = parse_u64(optarg, &samples_to_xfer);
  448. bytes_to_xfer = samples_to_xfer * 2ull;
  449. break;
  450. case 'b':
  451. baseband_filter_bw = true;
  452. result = parse_u32(optarg, &baseband_filter_bw_hz);
  453. break;
  454. default:
  455. printf("unknown argument '-%c %s'\n", opt, optarg);
  456. usage();
  457. return EXIT_FAILURE;
  458. }
  459. if( result != HACKRF_SUCCESS ) {
  460. printf("argument error: '-%c %s' %s (%d)\n", opt, optarg, hackrf_error_name(result), result);
  461. usage();
  462. return EXIT_FAILURE;
  463. }
  464. }
  465. if (samples_to_xfer >= SAMPLES_TO_XFER_MAX) {
  466. printf("argument error: num_samples must be less than %s/%sMio\n",
  467. u64toa(SAMPLES_TO_XFER_MAX,&ascii_u64_data1),
  468. u64toa((SAMPLES_TO_XFER_MAX/FREQ_ONE_MHZ),&ascii_u64_data2));
  469. usage();
  470. return EXIT_FAILURE;
  471. }
  472. if (if_freq || lo_freq || image_reject) {
  473. /* explicit tuning selected */
  474. if (!if_freq) {
  475. printf("argument error: if_freq_hz must be specified for explicit tuning.\n");
  476. usage();
  477. return EXIT_FAILURE;
  478. }
  479. if (!image_reject) {
  480. printf("argument error: image_reject must be specified for explicit tuning.\n");
  481. usage();
  482. return EXIT_FAILURE;
  483. }
  484. if (!lo_freq && (image_reject_selection != RF_PATH_FILTER_BYPASS)) {
  485. printf("argument error: lo_freq_hz must be specified for explicit tuning unless image_reject is set to bypass.\n");
  486. usage();
  487. return EXIT_FAILURE;
  488. }
  489. if ((if_freq_hz > IF_MAX_HZ) || (if_freq_hz < IF_MIN_HZ)) {
  490. printf("argument error: if_freq_hz shall be between %s and %s.\n",
  491. u64toa(IF_MIN_HZ,&ascii_u64_data1),
  492. u64toa(IF_MAX_HZ,&ascii_u64_data2));
  493. usage();
  494. return EXIT_FAILURE;
  495. }
  496. if ((lo_freq_hz > LO_MAX_HZ) || (lo_freq_hz < LO_MIN_HZ)) {
  497. printf("argument error: lo_freq_hz shall be between %s and %s.\n",
  498. u64toa(LO_MIN_HZ,&ascii_u64_data1),
  499. u64toa(LO_MAX_HZ,&ascii_u64_data2));
  500. usage();
  501. return EXIT_FAILURE;
  502. }
  503. if (image_reject_selection > 2) {
  504. printf("argument error: image_reject must be 0, 1, or 2 .\n");
  505. usage();
  506. return EXIT_FAILURE;
  507. }
  508. if (automatic_tuning) {
  509. printf("warning: freq_hz ignored by explicit tuning selection.\n");
  510. automatic_tuning = false;
  511. }
  512. switch (image_reject_selection) {
  513. case RF_PATH_FILTER_BYPASS:
  514. freq_hz = if_freq_hz;
  515. break;
  516. case RF_PATH_FILTER_LOW_PASS:
  517. freq_hz = abs(if_freq_hz - lo_freq_hz);
  518. break;
  519. case RF_PATH_FILTER_HIGH_PASS:
  520. freq_hz = if_freq_hz + lo_freq_hz;
  521. break;
  522. default:
  523. freq_hz = DEFAULT_FREQ_HZ;
  524. break;
  525. }
  526. printf("explicit tuning specified for %s Hz.\n",
  527. u64toa(freq_hz,&ascii_u64_data1));
  528. } else if (automatic_tuning) {
  529. if( (freq_hz > FREQ_MAX_HZ) || (freq_hz < FREQ_MIN_HZ) )
  530. {
  531. printf("argument error: freq_hz shall be between %s and %s.\n",
  532. u64toa(FREQ_MIN_HZ,&ascii_u64_data1),
  533. u64toa(FREQ_MAX_HZ,&ascii_u64_data2));
  534. usage();
  535. return EXIT_FAILURE;
  536. }
  537. } else {
  538. /* Use default freq */
  539. freq_hz = DEFAULT_FREQ_HZ;
  540. automatic_tuning = true;
  541. }
  542. if( amp ) {
  543. if( amp_enable > 1 )
  544. {
  545. printf("argument error: amp_enable shall be 0 or 1.\n");
  546. usage();
  547. return EXIT_FAILURE;
  548. }
  549. }
  550. if (antenna) {
  551. if (antenna_enable > 1) {
  552. printf("argument error: antenna_enable shall be 0 or 1.\n");
  553. usage();
  554. return EXIT_FAILURE;
  555. }
  556. }
  557. if( sample_rate == false )
  558. {
  559. sample_rate_hz = DEFAULT_SAMPLE_RATE_HZ;
  560. }
  561. if( baseband_filter_bw )
  562. {
  563. /* Compute nearest freq for bw filter */
  564. baseband_filter_bw_hz = hackrf_compute_baseband_filter_bw(baseband_filter_bw_hz);
  565. }else
  566. {
  567. /* Compute default value depending on sample rate */
  568. baseband_filter_bw_hz = hackrf_compute_baseband_filter_bw_round_down_lt(sample_rate_hz);
  569. }
  570. if (baseband_filter_bw_hz > BASEBAND_FILTER_BW_MAX) {
  571. printf("argument error: baseband_filter_bw_hz must be less or equal to %u Hz/%.03f MHz\n",
  572. BASEBAND_FILTER_BW_MAX, (float)(BASEBAND_FILTER_BW_MAX/FREQ_ONE_MHZ));
  573. usage();
  574. return EXIT_FAILURE;
  575. }
  576. if (baseband_filter_bw_hz < BASEBAND_FILTER_BW_MIN) {
  577. printf("argument error: baseband_filter_bw_hz must be greater or equal to %u Hz/%.03f MHz\n",
  578. BASEBAND_FILTER_BW_MIN, (float)(BASEBAND_FILTER_BW_MIN/FREQ_ONE_MHZ));
  579. usage();
  580. return EXIT_FAILURE;
  581. }
  582. if( (transmit == false) && (receive == receive_wav) )
  583. {
  584. printf("receive -r and receive_wav -w options are mutually exclusive\n");
  585. usage();
  586. return EXIT_FAILURE;
  587. }
  588. if( receive_wav == false )
  589. {
  590. if( transmit == receive )
  591. {
  592. if( transmit == true )
  593. {
  594. printf("receive -r and transmit -t options are mutually exclusive\n");
  595. } else
  596. {
  597. printf("specify either transmit -t or receive -r or receive_wav -w option\n");
  598. }
  599. usage();
  600. return EXIT_FAILURE;
  601. }
  602. }
  603. if( receive ) {
  604. transceiver_mode = TRANSCEIVER_MODE_RX;
  605. }
  606. if( transmit ) {
  607. transceiver_mode = TRANSCEIVER_MODE_TX;
  608. }
  609. if( receive_wav )
  610. {
  611. time (&rawtime);
  612. timeinfo = localtime (&rawtime);
  613. transceiver_mode = TRANSCEIVER_MODE_RX;
  614. /* File format HackRF Year(2013), Month(11), Day(28), Hour Min Sec+Z, Freq kHz, IQ.wav */
  615. strftime(date_time, DATE_TIME_MAX_LEN, "%Y%m%d_%H%M%S", timeinfo);
  616. snprintf(path_file, PATH_FILE_MAX_LEN, "HackRF_%sZ_%ukHz_IQ.wav", date_time, (uint32_t)(freq_hz/(1000ull)) );
  617. path = path_file;
  618. printf("Receive wav file: %s\n", path);
  619. }
  620. if( path == NULL ) {
  621. printf("specify a path to a file to transmit/receive\n");
  622. usage();
  623. return EXIT_FAILURE;
  624. }
  625. result = hackrf_init();
  626. if( result != HACKRF_SUCCESS ) {
  627. printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result);
  628. usage();
  629. return EXIT_FAILURE;
  630. }
  631. result = hackrf_open(&device);
  632. if( result != HACKRF_SUCCESS ) {
  633. printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result);
  634. usage();
  635. return EXIT_FAILURE;
  636. }
  637. if( transceiver_mode == TRANSCEIVER_MODE_RX )
  638. {
  639. fd = fopen(path, "wb");
  640. } else {
  641. fd = fopen(path, "rb");
  642. }
  643. if( fd == NULL ) {
  644. printf("Failed to open file: %s\n", path);
  645. return EXIT_FAILURE;
  646. }
  647. /* Change fd buffer to have bigger one to store or read data on/to HDD */
  648. result = setvbuf(fd , NULL , _IOFBF , FD_BUFFER_SIZE);
  649. if( result != 0 ) {
  650. printf("setvbuf() failed: %d\n", result);
  651. usage();
  652. return EXIT_FAILURE;
  653. }
  654. /* Write Wav header */
  655. if( receive_wav )
  656. {
  657. fwrite(&wave_file_hdr, 1, sizeof(t_wav_file_hdr), fd);
  658. }
  659. #ifdef _MSC_VER
  660. SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
  661. #else
  662. signal(SIGINT, &sigint_callback_handler);
  663. signal(SIGILL, &sigint_callback_handler);
  664. signal(SIGFPE, &sigint_callback_handler);
  665. signal(SIGSEGV, &sigint_callback_handler);
  666. signal(SIGTERM, &sigint_callback_handler);
  667. signal(SIGABRT, &sigint_callback_handler);
  668. #endif
  669. printf("call hackrf_sample_rate_set(%u Hz/%.03f MHz)\n", sample_rate_hz,((float)sample_rate_hz/(float)FREQ_ONE_MHZ));
  670. result = hackrf_set_sample_rate_manual(device, sample_rate_hz, 1);
  671. if( result != HACKRF_SUCCESS ) {
  672. printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result);
  673. usage();
  674. return EXIT_FAILURE;
  675. }
  676. printf("call hackrf_baseband_filter_bandwidth_set(%d Hz/%.03f MHz)\n",
  677. baseband_filter_bw_hz, ((float)baseband_filter_bw_hz/(float)FREQ_ONE_MHZ));
  678. result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hz);
  679. if( result != HACKRF_SUCCESS ) {
  680. printf("hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result);
  681. usage();
  682. return EXIT_FAILURE;
  683. }
  684. if( transceiver_mode == TRANSCEIVER_MODE_RX ) {
  685. result = hackrf_set_vga_gain(device, vga_gain);
  686. result |= hackrf_set_lna_gain(device, lna_gain);
  687. result |= hackrf_start_rx(device, rx_callback, NULL);
  688. } else {
  689. result = hackrf_set_txvga_gain(device, txvga_gain);
  690. result |= hackrf_start_tx(device, tx_callback, NULL);
  691. }
  692. if( result != HACKRF_SUCCESS ) {
  693. printf("hackrf_start_?x() failed: %s (%d)\n", hackrf_error_name(result), result);
  694. usage();
  695. return EXIT_FAILURE;
  696. }
  697. if (automatic_tuning) {
  698. printf("call hackrf_set_freq(%s Hz/%.03f MHz)\n",
  699. u64toa(freq_hz, &ascii_u64_data1),((double)freq_hz/(double)FREQ_ONE_MHZ) );
  700. result = hackrf_set_freq(device, freq_hz);
  701. if( result != HACKRF_SUCCESS ) {
  702. printf("hackrf_set_freq() failed: %s (%d)\n", hackrf_error_name(result), result);
  703. usage();
  704. return EXIT_FAILURE;
  705. }
  706. } else {
  707. printf("call hackrf_set_freq_explicit() with %s Hz IF, %s Hz LO, %s\n",
  708. u64toa(if_freq_hz,&ascii_u64_data1),
  709. u64toa(lo_freq_hz,&ascii_u64_data2),
  710. hackrf_filter_path_name(image_reject_selection));
  711. result = hackrf_set_freq_explicit(device, if_freq_hz, lo_freq_hz,
  712. image_reject_selection);
  713. if (result != HACKRF_SUCCESS) {
  714. printf("hackrf_set_freq_explicit() failed: %s (%d)\n",
  715. hackrf_error_name(result), result);
  716. usage();
  717. return EXIT_FAILURE;
  718. }
  719. }
  720. if( amp ) {
  721. printf("call hackrf_set_amp_enable(%u)\n", amp_enable);
  722. result = hackrf_set_amp_enable(device, (uint8_t)amp_enable);
  723. if( result != HACKRF_SUCCESS ) {
  724. printf("hackrf_set_amp_enable() failed: %s (%d)\n", hackrf_error_name(result), result);
  725. usage();
  726. return EXIT_FAILURE;
  727. }
  728. }
  729. if (antenna) {
  730. printf("call hackrf_set_antenna_enable(%u)\n", antenna_enable);
  731. result = hackrf_set_antenna_enable(device, (uint8_t)antenna_enable);
  732. if (result != HACKRF_SUCCESS) {
  733. printf("hackrf_set_antenna_enable() failed: %s (%d)\n", hackrf_error_name(result), result);
  734. usage();
  735. return EXIT_FAILURE;
  736. }
  737. }
  738. if( limit_num_samples ) {
  739. printf("samples_to_xfer %s/%sMio\n",
  740. u64toa(samples_to_xfer,&ascii_u64_data1),
  741. u64toa((samples_to_xfer/FREQ_ONE_MHZ),&ascii_u64_data2) );
  742. }
  743. gettimeofday(&t_start, NULL);
  744. gettimeofday(&time_start, NULL);
  745. printf("Stop with Ctrl-C\n");
  746. while( (hackrf_is_streaming(device) == HACKRF_TRUE) &&
  747. (do_exit == false) )
  748. {
  749. uint32_t byte_count_now;
  750. struct timeval time_now;
  751. float time_difference, rate;
  752. sleep(1);
  753. gettimeofday(&time_now, NULL);
  754. byte_count_now = byte_count;
  755. byte_count = 0;
  756. time_difference = TimevalDiff(&time_now, &time_start);
  757. rate = (float)byte_count_now / time_difference;
  758. printf("%4.1f MiB / %5.3f sec = %4.1f MiB/second\n",
  759. (byte_count_now / 1e6f), time_difference, (rate / 1e6f) );
  760. time_start = time_now;
  761. if (byte_count_now == 0) {
  762. exit_code = EXIT_FAILURE;
  763. printf("\nCouldn't transfer any bytes for one second.\n");
  764. break;
  765. }
  766. }
  767. result = hackrf_is_streaming(device);
  768. if (do_exit)
  769. {
  770. printf("\nUser cancel, exiting...\n");
  771. } else {
  772. printf("\nExiting... hackrf_is_streaming() result: %s (%d)\n", hackrf_error_name(result), result);
  773. }
  774. gettimeofday(&t_end, NULL);
  775. time_diff = TimevalDiff(&t_end, &t_start);
  776. printf("Total time: %5.5f s\n", time_diff);
  777. if(device != NULL)
  778. {
  779. if( receive )
  780. {
  781. result = hackrf_stop_rx(device);
  782. if( result != HACKRF_SUCCESS ) {
  783. printf("hackrf_stop_rx() failed: %s (%d)\n", hackrf_error_name(result), result);
  784. }else {
  785. printf("hackrf_stop_rx() done\n");
  786. }
  787. }
  788. if( transmit )
  789. {
  790. result = hackrf_stop_tx(device);
  791. if( result != HACKRF_SUCCESS ) {
  792. printf("hackrf_stop_tx() failed: %s (%d)\n", hackrf_error_name(result), result);
  793. }else {
  794. printf("hackrf_stop_tx() done\n");
  795. }
  796. }
  797. result = hackrf_close(device);
  798. if( result != HACKRF_SUCCESS )
  799. {
  800. printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result);
  801. }else {
  802. printf("hackrf_close() done\n");
  803. }
  804. hackrf_exit();
  805. printf("hackrf_exit() done\n");
  806. }
  807. if(fd != NULL)
  808. {
  809. if( receive_wav )
  810. {
  811. /* Get size of file */
  812. file_pos = ftell(fd);
  813. /* Update Wav Header */
  814. wave_file_hdr.hdr.size = file_pos+8;
  815. wave_file_hdr.fmt_chunk.dwSamplesPerSec = sample_rate_hz;
  816. wave_file_hdr.fmt_chunk.dwAvgBytesPerSec = wave_file_hdr.fmt_chunk.dwSamplesPerSec*2;
  817. wave_file_hdr.data_chunk.chunkSize = file_pos - sizeof(t_wav_file_hdr);
  818. /* Overwrite header with updated data */
  819. rewind(fd);
  820. fwrite(&wave_file_hdr, 1, sizeof(t_wav_file_hdr), fd);
  821. }
  822. fclose(fd);
  823. fd = NULL;
  824. printf("fclose(fd) done\n");
  825. }
  826. printf("exit\n");
  827. return exit_code;
  828. }