├── doc └── img │ ├── openwebrxcfg.png │ └── baudlinecfg_1.png ├── CMakeLists.txt ├── README.md └── play_sdr.c /doc/img/openwebrxcfg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hb9fxq/SDRPlayPorts/HEAD/doc/img/openwebrxcfg.png -------------------------------------------------------------------------------- /doc/img/baudlinecfg_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hb9fxq/SDRPlayPorts/HEAD/doc/img/baudlinecfg_1.png -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | project(SDRPlayPorts) 3 | 4 | link_directories(/usr/local/lib) 5 | 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 7 | 8 | add_executable(play_sdr play_sdr.c) 9 | 10 | target_link_libraries (play_sdr pthread m mirsdrapi-rsp) 11 | 12 | install (TARGETS play_sdr DESTINATION /usr/local/bin) 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SDRPlayPorts 2 | Ports of some parts of git://git.osmocom.org/rtl-sdr.git / http://sdr.osmocom.org/trac/wiki/rtl-sdr for the SDRPlay (http://www.sdrplay.com/) 3 | 4 | 5 | Incomplete!!! Actually not working yet ... Work in progress 6 | Prototype demo: 7 | * https://youtu.be/rDvxwpe5HT8 rtl_tcp first steps 8 | * https://youtu.be/aYnz0Auqwho play_sdr first steps 9 | 10 | # Installation 11 | 12 | 1. SDRPlay API 13 |
Download the SDRPlay linux api. 14 | * x86 32/64bit: http://www.sdrplay.com/linux.html 15 | * RaspberryPI: http://www.sdrplay.com/raspberrypi2.html 16 | 17 | and follow the instructions. 18 | 19 | 2. Build SDRPlayPorts: 20 |
 21 | git clone https://github.com/krippendorf/SDRPlayPorts.git
 22 | cd SDRPlayPorts
 23 | mkdir build && cd build
 24 | cmake ..
 25 | make
 26 | sudo make install
 27 | 
28 | 29 | # Todo 30 | * Test, refactor and enhance ;-) 31 | 32 | ## Samples 33 | * Use with OpenWebRx / Config file: 34 | 35 | Very unstable with play_sdr so far... 36 | 37 | I've tried the 16 bit (-x 16 switch and csdr convert_s16_f) and 8bit variant, but no luck so far, maybe you? 38 | Check for aliasing, mirrors, before reporting success ;) 39 | 40 | 41 | ```python 42 | # ==== DSP/RX settings ==== 43 | dsp_plugin="csdr" 44 | fft_fps=9 45 | fft_size=4096 46 | samp_rate = 1024000 47 | center_freq = 3600000 48 | rf_gain = 35 #in dB. For an RTL-SDR, rf_gain=0 will set the tuner to auto gain mode, else it will be in manual gain mode. 49 | ppm = 0 50 | 51 | audio_compression="adpcm" #valid values: "adpcm", "none" 52 | fft_compression="adpcm" #valid values: "adpcm", "none" 53 | 54 | start_rtl_thread=True 55 | 56 | # ==== I/Q sources (uncomment the appropriate) ==== 57 | 58 | # >> RTL-SDR via rtl_sdr 59 | 60 | start_rtl_command="play_sdr -b 600 -s {samp_rate} -f {center_freq} -x 16 -g {rf_gain} -y 0 -".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate, ppm=ppm) 61 | format_conversion="csdr convert_s16_f" 62 | 63 | ``` 64 | ![SDRPlay with OpenWebRX, 16bit option set](https://raw.githubusercontent.com/krippendorf/SDRPlayPorts/master/doc/img/openwebrxcfg.png) 65 | * Use with Baudline 66 | 67 | 68 | ```bash 69 | timeout 15s play_sdr -s 8000000 -b 600 -f 3.6M -g 35 -l 0 -x 16 8000000_16bit.raw 70 | ``` 71 | ![SDRPlay with Baudline, 16bit option set](https://raw.githubusercontent.com/krippendorf/SDRPlayPorts/master/doc/img/baudlinecfg_1.png) 72 | 73 | 74 | 75 | # License 76 | 77 | ##SDRPlayPorts Licence 78 | 79 | 80 | SDRPlayPorts 81 | Ports of some parts of rtl-sdr for the SDRPlay (git://git.osmocom.org/rtl-sdr.git /) 82 | Fork by HB9FXQ (Frank Werner-Krippendorf, mail@hb9fxq.ch) 83 | 84 | This program is free software: you can redistribute it and/or modify 85 | it under the terms of the GNU General Public License as published by 86 | the Free Software Foundation, either version 2 of the License, or 87 | (at your option) any later version. 88 | 89 | This program is distributed in the hope that it will be useful, 90 | but WITHOUT ANY WARRANTY; without even the implied warranty of 91 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 92 | GNU General Public License for more details. 93 | 94 | You should have received a copy of the GNU General Public License 95 | along with this program. If not, see . 96 | 97 | 98 | 99 | ##rtl-sdr Licence 100 | 101 | 102 | rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 103 | Copyright (C) 2012 by Steve Markgraf 104 | Copyright (C) 2012-2013 by Hoernchen 105 | 106 | This program is free software: you can redistribute it and/or modify 107 | it under the terms of the GNU General Public License as published by 108 | the Free Software Foundation, either version 2 of the License, or 109 | (at your option) any later version. 110 | 111 | This program is distributed in the hope that it will be useful, 112 | but WITHOUT ANY WARRANTY; without even the implied warranty of 113 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 114 | GNU General Public License for more details. 115 | 116 | You should have received a copy of the GNU General Public License 117 | along with this program. If not, see . 118 | 119 | 120 | -------------------------------------------------------------------------------- /play_sdr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * Copyright (C) 2012 by Steve Markgraf 4 | * Copyright (C) 2012-2013 by Hoernchen 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 . 18 | * 19 | * ************************************** THIS IS A FORK ******************* ORIGINAL COPYRIGHT SEE ABOVE. 20 | * 21 | * 22 | 23 | 24 | __/\\\________/\\\__/\\\\\\\\\\\\\________/\\\\\\\\\_____/\\\\\\\\\\\\\\\__/\\\_______/\\\________/\\\_______ 25 | _\/\\\_______\/\\\_\/\\\/////////\\\____/\\\///////\\\__\/\\\///////////__\///\\\___/\\\/______/\\\\/\\\\____ 26 | _\/\\\_______\/\\\_\/\\\_______\/\\\___/\\\______\//\\\_\/\\\_______________\///\\\\\\/______/\\\//\////\\\__ 27 | _\/\\\\\\\\\\\\\\\_\/\\\\\\\\\\\\\\___\//\\\_____/\\\\\_\/\\\\\\\\\\\_________\//\\\\_______/\\\______\//\\\_ 28 | _\/\\\/////////\\\_\/\\\/////////\\\___\///\\\\\\\\/\\\_\/\\\///////___________\/\\\\______\//\\\______/\\\__ 29 | _\/\\\_______\/\\\_\/\\\_______\/\\\_____\////////\/\\\_\/\\\__________________/\\\\\\______\///\\\\/\\\\/___ 30 | _\/\\\_______\/\\\_\/\\\_______\/\\\___/\\________/\\\__\/\\\________________/\\\////\\\______\////\\\//_____ 31 | _\/\\\_______\/\\\_\/\\\\\\\\\\\\\/___\//\\\\\\\\\\\/___\/\\\______________/\\\/___\///\\\_______\///\\\\\\__ 32 | _\///________\///__\/////////////______\///////////_____\///______________\///_______\///__________\//////___ 33 | 34 | * 35 | * 36 | * 37 | * 38 | * SDRPlayPorts 39 | * Ports of some parts of rtl-sdr for the SDRPlay (original: git://git.osmocom.org/rtl-sdr.git /) 40 | * 2016: Fork by HB9FXQ (Frank Werner-Krippendorf, mail@hb9fxq.ch) 41 | * 42 | * Code changes I've done: 43 | * - removed rtl_sdr related calls and replaced them with mir_* to work with the SDRPlay 44 | * - removed various local variables 45 | * 46 | * This program is free software: you can redistribute it and/or modify 47 | * it under the terms of the GNU General Public License as published by 48 | * the Free Software Foundation, either version 2 of the License, or 49 | * (at your option) any later version. 50 | * 51 | * This program is distributed in the hope that it will be useful, 52 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 53 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 54 | * GNU General Public License for more details. 55 | * 56 | * You should have received a copy of the GNU General Public License 57 | * along with this program. If not, see . 58 | * 59 | * 60 | * 61 | */ 62 | 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | #include 71 | #include "mirsdrapi-rsp.h" 72 | 73 | 74 | #define DEFAULT_SAMPLE_RATE 2048000 75 | #define DEFAULT_LNA 0; 76 | #define DEFAULT_AGC_SETPOINT -30; 77 | #define DEFAULT_FREQUENCY 100000000; 78 | #define DEFAULT_RESULT_BITS 8; // more compatible with RTL_SDR 79 | 80 | static int do_exit = 0; 81 | 82 | int samplesPerPacket; 83 | int resultBits = DEFAULT_RESULT_BITS; 84 | int flipComplex = 0; 85 | uint8_t *buffer8; 86 | short *buffer16; 87 | FILE *file; 88 | 89 | void* context = NULL; /* currently unused - let the API the thread stuff */ 90 | 91 | 92 | void adjust_bw(int bwHz, mir_sdr_Bw_MHzT *ptr); 93 | void adjust_if(int ifFreq, mir_sdr_If_kHzT *ptr); 94 | void adjust_result_bits(int bits, int *ptrResultBits); 95 | 96 | 97 | double atofs(char *s) 98 | /* standard suffixes */ 99 | { 100 | char last; 101 | int len; 102 | double suff = 1.0; 103 | len = strlen(s); 104 | last = s[len - 1]; 105 | s[len - 1] = '\0'; 106 | switch (last) { 107 | case 'g': 108 | case 'G': 109 | suff *= 1e3; 110 | case 'm': 111 | case 'M': 112 | suff *= 1e3; 113 | case 'k': 114 | case 'K': 115 | suff *= 1e3; 116 | suff *= atof(s); 117 | s[len - 1] = last; 118 | return suff; 119 | } 120 | s[len - 1] = last; 121 | return atof(s); 122 | } 123 | 124 | 125 | void usage(void) { 126 | fprintf(stderr, 127 | "play_sdr, an I/Q recorder for SDRplay RSP receivers\n\n" 128 | "Usage:\t -f frequency_to_tune_to (Hz)\n" 129 | "\t[-s samplerate (default: 2048000 Hz)]\n" 130 | "\t[-b Band width in kHz (default: 1536) possible values: 200 300 600 1536 5000 6000 7000 8000]\n" 131 | "\t[-i IF in kHz (default: 0 (=Zero IF)) possible values: 0 450 1620 2048]\n" 132 | "\t[-r ADC set point is in dBfs\n" 133 | "(decibels relative to full scale) and will normally lie in the range 0dBfs (full scale) to -50dBfs (50dB below\n" 134 | "full scale). Default: -30)]\n\n" 135 | "\t[-l RSP LNA enable (default: 0, disabled)]\n" 136 | "\t[-y Flipcomplex I-Q => Q-I (default: 0, disabled) 1 = enabled\n" 137 | "\t[-x Result I/Q bit resolution (uint8 / short) (default: 8, possible values: 8 16)]\n" 138 | "\t[-v Verbose mode, prints debug information. Default 0, 1 = enabled\n" 139 | "\tfilename (a '-' dumps samples to stdout)\n\n"); 140 | exit(1); 141 | } 142 | 143 | void callbackGC(unsigned int gRdB, unsigned int lnaGRdB, void *cbContext) 144 | { 145 | return; 146 | } 147 | 148 | unsigned int firstBufferCallback = 1; 149 | 150 | void streamCallback (short *xi, short *xq, unsigned int firstSampleNum, int grChanged, int rfChanged, int fsChanged, unsigned int numSamples, unsigned int reset, void *cbContext){ 151 | 152 | 153 | if(firstBufferCallback == 1 || reset == 1){ 154 | 155 | if (resultBits == 8) { 156 | buffer8 = malloc(numSamples * 2 * sizeof(uint8_t)); 157 | } 158 | else { 159 | buffer16 = malloc(numSamples * 2 * sizeof(short)); 160 | } 161 | 162 | firstBufferCallback = 0; 163 | } 164 | 165 | int j = 0; 166 | int i = 0; 167 | 168 | for (i = 0; i < numSamples; i++) { 169 | if (resultBits == 8) { 170 | if (flipComplex == 0) { 171 | buffer8[j++] = (unsigned char) (xi[i] >> 8); 172 | buffer8[j++] = (unsigned char) (xq[i] >> 8); 173 | } else { 174 | buffer8[j++] = (unsigned char) (xq[i] >> 8); 175 | buffer8[j++] = (unsigned char) (xi[i] >> 8); 176 | } 177 | } 178 | else { 179 | if (flipComplex == 0) { 180 | buffer16[j++] = (xi[i]); 181 | buffer16[j++] = (xq[i]); 182 | } else { 183 | buffer16[j++] = (xq[i]); 184 | buffer16[j++] = (xi[i]); 185 | } 186 | } 187 | } 188 | 189 | if (resultBits == 8) { 190 | if (fwrite(buffer8, sizeof(uint8_t), numSamples*2, file) != (size_t) numSamples*2) { 191 | fprintf(stderr, "Short write, samples lost, exiting 8!\n"); // TODO: take firstSampleNum into account 192 | return; 193 | } 194 | } 195 | else { 196 | if (fwrite(buffer16, sizeof(short), numSamples * 2, file) != (size_t) numSamples*2) { 197 | fprintf(stderr, "Short write, samples lost, exiting 16!\n"); // TODO: take firstSampleNum into account 198 | return; 199 | } 200 | } 201 | } 202 | 203 | static void sighandler(int signum) { 204 | fprintf(stderr, "Signal (%d) caught, exiting!\n", signum); 205 | do_exit = 1; 206 | } 207 | 208 | int main(int argc, char **argv) { 209 | 210 | struct sigaction sigact; 211 | char *filename = NULL; 212 | mir_sdr_ErrT r; 213 | int opt; 214 | int agcSetPoint = DEFAULT_AGC_SETPOINT; 215 | int verbose = 0; 216 | 217 | uint32_t frequency = DEFAULT_FREQUENCY; 218 | uint32_t samp_rate = DEFAULT_SAMPLE_RATE; 219 | int rspLNA = DEFAULT_LNA; 220 | 221 | int i, j; 222 | 223 | mir_sdr_Bw_MHzT bandwidth = mir_sdr_BW_1_536; 224 | mir_sdr_If_kHzT ifKhz = mir_sdr_IF_Zero; 225 | 226 | while ((opt = getopt(argc, argv, "f:g:s:n:l:b:i:x:y:v:")) != -1) { 227 | switch (opt) { 228 | case 'f': 229 | frequency = (uint32_t) atofs(optarg); 230 | break; 231 | case 'g': 232 | agcSetPoint = (int) atof(optarg); 233 | break; 234 | case 's': 235 | samp_rate = (uint32_t) atofs(optarg); 236 | break; 237 | case 'l': 238 | rspLNA = atoi(optarg); 239 | break; 240 | case 'b': 241 | adjust_bw(atoi(optarg), &bandwidth); 242 | break; 243 | case 'i': 244 | adjust_if(atoi(optarg), &ifKhz); 245 | break; 246 | case 'x': 247 | adjust_result_bits(atoi(optarg), &resultBits); 248 | break; 249 | case 'y': 250 | flipComplex = atoi(optarg); 251 | break; 252 | case 'v': 253 | verbose = atoi(optarg); 254 | break; 255 | default: 256 | usage(); 257 | break; 258 | } 259 | } 260 | 261 | if (argc <= optind) { 262 | usage(); 263 | } else { 264 | filename = argv[optind]; 265 | } 266 | 267 | if (verbose == 1) { 268 | fprintf(stderr, "[DEBUG] *************** play_sdr init summary *********************\n"); 269 | fprintf(stderr, "[DEBUG] LNA: %d\n", rspLNA); 270 | fprintf(stderr, "[DEBUG] samp_rate: %d\n", samp_rate); 271 | fprintf(stderr, "[DEBUG] agcSetPoint: %d\n", agcSetPoint); 272 | fprintf(stderr, "[DEBUG] frequency: [Hz] %d / [MHz] %f\n", frequency, frequency / 1e6); 273 | fprintf(stderr, "[DEBUG] bandwidth: [kHz] %d\n", bandwidth); 274 | fprintf(stderr, "[DEBUG] IF: %d\n", ifKhz); 275 | fprintf(stderr, "[DEBUG] Result I/Q bit resolution (bit): %d\n", resultBits); 276 | fprintf(stderr, "[DEBUG] *************************************************************\n"); 277 | } 278 | 279 | 280 | sigact.sa_handler = sighandler; 281 | sigemptyset(&sigact.sa_mask); 282 | sigact.sa_flags = 0; 283 | sigaction(SIGINT, &sigact, NULL); 284 | sigaction(SIGTERM, &sigact, NULL); 285 | sigaction(SIGQUIT, &sigact, NULL); 286 | sigaction(SIGPIPE, &sigact, NULL); 287 | 288 | 289 | if (strcmp(filename, "-") == 0) { /* Write samples to stdout */ 290 | file = stdout; 291 | } else { 292 | file = fopen(filename, "wb"); 293 | if (!file) { 294 | fprintf(stderr, "Failed to open %s\n", filename); 295 | goto out; 296 | } 297 | } 298 | 299 | 300 | mir_sdr_AgcControl(1, agcSetPoint, 0, 0, 0, 0, rspLNA); 301 | 302 | int infoOverallGr; 303 | r = mir_sdr_StreamInit(&agcSetPoint, (samp_rate/1e6), (frequency/1e6), mir_sdr_BW_1_536, mir_sdr_IF_Zero, rspLNA, &infoOverallGr, 1 /* use internal gr tables acording to band */, &samplesPerPacket, streamCallback, 304 | callbackGC, &context); 305 | 306 | 307 | if (r != mir_sdr_Success) { 308 | fprintf(stderr, "Failed to start SDRplay RSP device.\n"); 309 | exit(r); 310 | } 311 | 312 | 313 | mir_sdr_SetDcMode(4, 0); 314 | mir_sdr_SetDcTrackTime(63); 315 | 316 | 317 | fprintf(stderr, "Writing samples...\n"); 318 | while (!do_exit) { 319 | sleep(1); 320 | } 321 | 322 | if (do_exit) 323 | fprintf(stderr, "\nUser cancel, exiting...\n"); 324 | else 325 | fprintf(stderr, "\nLibrary error %d, exiting...\n", r); 326 | 327 | if (file != stdout) 328 | fclose(file); 329 | 330 | 331 | if (resultBits == 8) { 332 | free(buffer8); 333 | } 334 | else { 335 | free(buffer16); 336 | } 337 | 338 | out: 339 | return r >= 0 ? r : -r; 340 | } 341 | 342 | void adjust_result_bits(int bits, int *ptrResultBits) { 343 | switch (bits) { 344 | case 8: 345 | case 16: 346 | *ptrResultBits = bits; 347 | return; 348 | } 349 | 350 | fprintf(stderr, "Invalid result I/Q resolution (-x) !\n"); 351 | usage(); 352 | } 353 | 354 | void adjust_if(int ifFreq, mir_sdr_If_kHzT *ptrIFKhz) { 355 | switch (ifFreq) { 356 | case 0: 357 | case 450: 358 | case 1620: 359 | case 2048: 360 | *ptrIFKhz = ifFreq; 361 | return; 362 | } 363 | 364 | fprintf(stderr, "Invalid IF frequency (-i) !\n"); 365 | usage(); 366 | 367 | } 368 | 369 | void adjust_bw(int bwHz, mir_sdr_Bw_MHzT *ptrBw) { 370 | 371 | switch (bwHz) { 372 | case 200: 373 | case 300: 374 | case 600: 375 | case 1536: 376 | case 5000: 377 | case 6000: 378 | case 8000: 379 | *ptrBw = bwHz; 380 | return; 381 | } 382 | 383 | fprintf(stderr, "Invalid Band Width (-b) !\n"); 384 | usage(); 385 | } --------------------------------------------------------------------------------