input-rtlsdr.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. * input-rtlsdr.cpp
  3. * RTLSDR-specific routines
  4. *
  5. * Copyright (c) 2015-2021 Tomasz Lemiech <szpajder@gmail.com>
  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 3 of the License, or
  10. * (at your option) 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. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "input-rtlsdr.h" // rtlsdr_dev_data_t
  21. #include <assert.h>
  22. #include <limits.h> // SCHAR_MAX
  23. #include <rtl-sdr.h>
  24. #include <stdint.h> // uint32_t
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <syslog.h> // FIXME: get rid of this
  29. #include <iostream>
  30. #include <libconfig.h++> // Setting
  31. #include "input-common.h" // input_t, sample_format_t, input_state_t, MODULE_EXPORT
  32. #include "input-helpers.h" // circbuffer_append
  33. #include "rtl_airband.h" // do_exit, fft_size, debug_print, XCALLOC, error()
  34. using namespace std;
  35. static void rtlsdr_callback(unsigned char* buf, uint32_t len, void* ctx) {
  36. if (do_exit)
  37. return;
  38. input_t* input = (input_t*)ctx;
  39. circbuffer_append(input, buf, (size_t)len);
  40. }
  41. /* based on librtlsdr-keenerd, (c) Kyle Keen */
  42. static bool rtlsdr_nearest_gain(rtlsdr_dev_t* dev, int target_gain, int* nearest) {
  43. assert(nearest != NULL);
  44. int i, r, err1, err2, count;
  45. int* gains;
  46. r = rtlsdr_set_tuner_gain_mode(dev, 1);
  47. if (r < 0) {
  48. return false;
  49. }
  50. count = rtlsdr_get_tuner_gains(dev, NULL);
  51. if (count <= 0) {
  52. return false;
  53. }
  54. gains = (int*)XCALLOC(count, sizeof(int));
  55. count = rtlsdr_get_tuner_gains(dev, gains);
  56. *nearest = gains[0];
  57. for (i = 0; i < count; i++) {
  58. err1 = abs(target_gain - *nearest);
  59. err2 = abs(target_gain - gains[i]);
  60. if (err2 < err1) {
  61. *nearest = gains[i];
  62. }
  63. }
  64. free(gains);
  65. return true;
  66. }
  67. static int rtlsdr_find_device_by_serial(char const* const s) {
  68. char vendor[256] = {0}, product[256] = {0}, serial[256] = {0};
  69. int count = rtlsdr_get_device_count();
  70. if (count < 1) {
  71. return -1;
  72. }
  73. for (int i = 0; i < count; i++) {
  74. rtlsdr_get_device_usb_strings(i, vendor, product, serial);
  75. if (strcmp(s, serial) != 0) {
  76. continue;
  77. }
  78. return i;
  79. }
  80. return -1;
  81. }
  82. int rtlsdr_init(input_t* const input) {
  83. rtlsdr_dev_data_t* dev_data = (rtlsdr_dev_data_t*)input->dev_data;
  84. if (dev_data->serial != NULL) {
  85. dev_data->index = rtlsdr_find_device_by_serial(dev_data->serial);
  86. if (dev_data->index < 0) {
  87. cerr << "RTLSDR device with serial number " << dev_data->serial << " not found\n";
  88. error();
  89. }
  90. }
  91. dev_data->dev = NULL;
  92. rtlsdr_open(&dev_data->dev, dev_data->index);
  93. if (NULL == dev_data->dev) {
  94. log(LOG_ERR, "Failed to open rtlsdr device #%d.\n", dev_data->index);
  95. error();
  96. }
  97. rtlsdr_dev_t* rtl = dev_data->dev;
  98. int r = rtlsdr_set_sample_rate(rtl, input->sample_rate);
  99. if (r < 0) {
  100. log(LOG_ERR, "Failed to set sample rate for device #%d. Error %d.\n", dev_data->index, r);
  101. }
  102. r = rtlsdr_set_center_freq(rtl, input->centerfreq);
  103. if (r < 0) {
  104. log(LOG_ERR, "Failed to set center freq for device #%d. Error %d.\n", dev_data->index, r);
  105. }
  106. r = rtlsdr_set_freq_correction(rtl, dev_data->correction);
  107. if (r < 0 && r != -2) {
  108. log(LOG_ERR, "Failed to set freq correction for device #%d. Error %d.\n", dev_data->index, r);
  109. }
  110. // Fitipower FC0012 gain needs to be initialized to its lowest value before setting it to the desired value
  111. if (rtlsdr_get_tuner_type(rtl) == RTLSDR_TUNER_FC0012) {
  112. int initialGain = 0;
  113. if (rtlsdr_nearest_gain(rtl, -99, &initialGain) != true) {
  114. log(LOG_ERR, "Failed to read supported gain list for device #%d\n", dev_data->index);
  115. error();
  116. }
  117. r |= rtlsdr_set_tuner_gain(rtl, initialGain);
  118. if (r < 0) {
  119. log(LOG_ERR, "Failed to initialize gain for device #%d: error %d\n", (float)initialGain / 10.f, dev_data->index, r);
  120. }
  121. }
  122. int ngain = 0;
  123. if (rtlsdr_nearest_gain(rtl, dev_data->gain, &ngain) != true) {
  124. log(LOG_ERR, "Failed to read supported gain list for device #%d\n", dev_data->index);
  125. error();
  126. }
  127. r = rtlsdr_set_tuner_gain_mode(rtl, 1);
  128. r |= rtlsdr_set_tuner_gain(rtl, ngain);
  129. if (r < 0) {
  130. log(LOG_ERR, "Failed to set gain to %0.2f for device #%d: error %d\n", (float)ngain / 10.f, dev_data->index, r);
  131. } else {
  132. log(LOG_INFO, "Device #%d: gain set to %0.2f dB\n", dev_data->index, (float)rtlsdr_get_tuner_gain(rtl) / 10.f);
  133. }
  134. r = rtlsdr_set_agc_mode(rtl, 0);
  135. if (r < 0) {
  136. log(LOG_ERR, "Failed to disable AGC for device #%d. Error %d.\n", dev_data->index, r);
  137. }
  138. rtlsdr_reset_buffer(rtl);
  139. log(LOG_INFO, "RTLSDR device %d initialized\n", dev_data->index);
  140. return 0;
  141. }
  142. void* rtlsdr_rx_thread(void* ctx) {
  143. input_t* input = (input_t*)ctx;
  144. rtlsdr_dev_data_t* dev_data = (rtlsdr_dev_data_t*)input->dev_data;
  145. assert(dev_data->dev != NULL);
  146. input->state = INPUT_RUNNING;
  147. if (rtlsdr_read_async(dev_data->dev, rtlsdr_callback, ctx, dev_data->bufcnt, RTLSDR_BUFSIZE) < 0) {
  148. log(LOG_ERR, "RTLSDR device #%d: async read failed, disabling\n", dev_data->index);
  149. input->state = INPUT_FAILED;
  150. }
  151. return 0;
  152. }
  153. int rtlsdr_stop(input_t* const input) {
  154. rtlsdr_dev_data_t* dev_data = (rtlsdr_dev_data_t*)input->dev_data;
  155. assert(dev_data->dev != NULL);
  156. if (rtlsdr_cancel_async(dev_data->dev) < 0) {
  157. return -1;
  158. }
  159. return rtlsdr_close(dev_data->dev);
  160. }
  161. int rtlsdr_set_centerfreq(input_t* const input, int const centerfreq) {
  162. rtlsdr_dev_data_t* dev_data = (rtlsdr_dev_data_t*)input->dev_data;
  163. assert(dev_data->dev != NULL);
  164. int r = rtlsdr_set_center_freq(dev_data->dev, centerfreq);
  165. if (r < 0) {
  166. log(LOG_ERR, "Failed to set centerfreq for RTLSDR device #%d: error %d\n", dev_data->index, r);
  167. return -1;
  168. }
  169. return 0;
  170. }
  171. int rtlsdr_parse_config(input_t* const input, libconfig::Setting& cfg) {
  172. rtlsdr_dev_data_t* dev_data = (rtlsdr_dev_data_t*)input->dev_data;
  173. if (cfg.exists("serial")) {
  174. dev_data->serial = strdup(cfg["serial"]);
  175. } else if (cfg.exists("index")) {
  176. dev_data->index = (int)cfg["index"];
  177. } else {
  178. cerr << "RTLSDR configuration error: no index and no serial number given\n";
  179. error();
  180. }
  181. if (cfg.exists("gain")) {
  182. if (cfg["gain"].getType() == libconfig::Setting::TypeInt) { // backward compatibility
  183. dev_data->gain = (int)cfg["gain"] * 10;
  184. } else if (cfg["gain"].getType() == libconfig::Setting::TypeFloat) {
  185. dev_data->gain = (int)((float)cfg["gain"] * 10.0f);
  186. }
  187. } else {
  188. cerr << "RTLSDR configuration error: gain is not configured\n";
  189. error();
  190. }
  191. if (cfg.exists("correction")) {
  192. dev_data->correction = (int)cfg["correction"];
  193. }
  194. if (cfg.exists("buffers")) {
  195. dev_data->bufcnt = (int)(cfg["buffers"]);
  196. if (dev_data->bufcnt < 1) {
  197. cerr << "RTLSDR configuration error: buffers must be greater than 0\n";
  198. error();
  199. }
  200. }
  201. return 0;
  202. }
  203. MODULE_EXPORT input_t* rtlsdr_input_new() {
  204. rtlsdr_dev_data_t* dev_data = (rtlsdr_dev_data_t*)XCALLOC(1, sizeof(rtlsdr_dev_data_t));
  205. dev_data->index = -1; // invalid default receiver index
  206. dev_data->gain = -1; // invalid default gain value
  207. dev_data->bufcnt = RTLSDR_DEFAULT_LIBUSB_BUFFER_COUNT;
  208. /* return &( input_t ){
  209. .dev_data = dev_data,
  210. .state = INPUT_UNKNOWN,
  211. .sfmt = SFMT_U8,
  212. .sample_rate = RTLSDR_DEFAULT_SAMPLE_RATE,
  213. .parse_config = &rtlsdr_parse_config,
  214. .init = &rtlsdr_init,
  215. .run_rx_thread = &rtlsdr_rx_thread,
  216. .set_centerfreq = &rtlsdr_set_centerfreq,
  217. .stop = &rtlsdr_stop
  218. }; */
  219. input_t* input = (input_t*)XCALLOC(1, sizeof(input_t));
  220. input->dev_data = dev_data;
  221. input->state = INPUT_UNKNOWN;
  222. input->sfmt = SFMT_U8;
  223. input->fullscale = (float)SCHAR_MAX - 0.5f;
  224. input->bytes_per_sample = sizeof(unsigned char);
  225. input->sample_rate = RTLSDR_DEFAULT_SAMPLE_RATE;
  226. input->parse_config = &rtlsdr_parse_config;
  227. input->init = &rtlsdr_init;
  228. input->run_rx_thread = &rtlsdr_rx_thread;
  229. input->set_centerfreq = &rtlsdr_set_centerfreq;
  230. input->stop = &rtlsdr_stop;
  231. return input;
  232. }