diff --git a/CMakeLists.txt b/CMakeLists.txt index ed5fb83..cb15801 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,11 +137,11 @@ else() endif() message ( STATUS "Using libairspy: ${WITH_AIR}") -option(SDRPLAY "Enable SDRplay support via API version 2" ON) +option(SDRPLAY "Enable SDRplay support via API version 3" ON) if(SDRPLAY) SET(WITH_SDRPLAY NO) - find_library(LIBPLAY mirsdrapi-rsp) + find_library(LIBPLAY sdrplay_api) if(LIBPLAY) add_definitions(-DWITH_SDRPLAY ) target_sources( acarsdec PRIVATE sdrplay.c) @@ -151,7 +151,7 @@ if(SDRPLAY) else() SET(WITH_SDRPLAY DISABLED) endif() -message ( STATUS "Using libmirsdrapi-rsp: ${WITH_SDRPLAY}") +message ( STATUS "Using sdrplay_api: ${WITH_SDRPLAY}") option(SOAPYSDR "Enable SoapySDR support" ON) diff --git a/README.md b/README.md index 74b3092..14636c7 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ It depends on some optional external libraries : * librtlsdr for RTL-based SDR input (http://sdr.osmocom.org/trac/wiki/rtl-sdr) * libsoapysdr for SoapySDR input (https://github.com/pothosware/SoapySDR) * libairspy for airspy SDR input (https://github.com/airspy/airspyone_host) - * libmirsdrapi-rsp for sdrplay software radio input + * libsdrplay_api for sdrplay software radio input * libsndfile for audio input (https://github.com/libsndfile/libsndfile) * libasound for ALSA input (https://github.com/alsa-project/alsa-lib) * libacars for decoding ATS applications (https://github.com/szpajder/libacars) @@ -199,13 +199,19 @@ DESTPARAMS are: Note: acarsdec will try to set the R820T tuner bandwidth to suit given frequencies. See https://tleconte.github.io/R820T/r820IF.html -#### SDRplay (untested, uses legacy v2 API - help wanted) +#### SDRplay (API version 3.15 and above) ``` --sdrplay decode from sdrplay + -a set antenna port to use (default: first antenna) -c set center frequency to tune to in MHz, e.g. 131.800 (default: automatic) - -G gain reduction in dB's, range 20 .. 59 (default: -100 is autogain) + -R sample rate in kHz - must be a multiple of 12, range 72 .. 10000 (default: 3024) + -W IF bandwidth in kHz - one of: 200, 300, 600, 1536, 5000, 6000, 7000, and 8000 (default: 1536) + -G gain reduction in dB's, range 20 .. 59 (default: -100 is autogain) -L set the lnaState (depends on the device) + -n enable notch filter - one of RF, FM, DAB, or RSPduo-AM (default: none enabled) + -p set ppm frequency correction (default: 0) + -B enable (1) or disable (0) the bias tee (default is 0) ``` All SDR sources described above expect a list of frequencies ` [ [...]]` to decode from, expressed in decimal MHz diff --git a/acarsdec.c b/acarsdec.c index 6cb4507..ebad50f 100644 --- a/acarsdec.c +++ b/acarsdec.c @@ -172,9 +172,15 @@ static void usage(void) fprintf(stderr, "\n sdrplayopts:\n" " --sdrplay\t\t: decode from sdrplay\n" + " -a \t\t: set antenna port to use (default: first antenna)\n" " -c \t\t: set center frequency to tune to in MHz, e.g. 131.800 (default: automatic)\n" - " -G \t\t: gain reduction in dB's, range 20 .. 59 (default: -100 is autogain)\n" - " -L \t: set the lnaState (depends on the device)\n"); + " -R \t: sample rate in kHz - must be a multiple of 12, range 72 .. 10000 (default: 3024)\n" + " -W \t\t: IF bandwidth in kHz - one of: 200, 300, 600, 1536, 5000, 6000, 7000, and 8000 (default: depends on sample rate)\n" + " -G \t\t: gain reduction in dB's, range 20 .. 59 (default: -100 is autogain)\n" + " -L \t\t: set the lnaState (depends on the device)\n" + " -n \t: enable notch filter - one of RF, FM, DAB, or RSPduo-AM (default: none enabled)\n" + " -p \t\t: set ppm frequency correction (default: 0)\n" + " -B \t\t: enable (1) or disable (0) the bias tee (default is 0)\n"); #endif #ifdef WITH_SOAPY fprintf(stderr, @@ -262,6 +268,7 @@ int main(int argc, char **argv) int c; int res; unsigned int n; + unsigned int sr; struct sigaction sigact; struct option long_opts[] = { #ifdef WITH_ALSA @@ -277,7 +284,7 @@ int main(int argc, char **argv) { "airspy", required_argument, NULL, IN_AIR }, #endif #ifdef WITH_SDRPLAY - { "sdrplay", no_argument, NULL, IN_SDRPLAY }, + { "sdrplay", required_argument, NULL, IN_SDRPLAY }, #endif #ifdef WITH_SOAPY { "soapysdr", required_argument, NULL, IN_SOAPY }, @@ -299,7 +306,7 @@ int main(int argc, char **argv) R.idstation = strdup(sys_hostname); res = 0; - while ((c = getopt_long(argc, argv, "hvt:g:m:a:Aep:c:i:L:G:b:B:", long_opts, NULL)) != EOF) { + while ((c = getopt_long(argc, argv, "hvt:g:m:a:Aep:c:i:R:W:L:G:n:b:B:", long_opts, NULL)) != EOF) { switch (c) { case -2: res = setup_output(optarg); @@ -364,12 +371,35 @@ int main(int argc, char **argv) if (R.inmode) errx(-1, "Only 1 input allowed"); R.inmode = IN_SDRPLAY; + inarg = optarg; + break; + case 'R': + sr = (unsigned)atoi(optarg); + if (sr % (INTRATE / 1000)) + errx(-1, "Invalid sample rate (not a multiple of 12k)"); + if (sr < 72 || sr > 10000) + errx(-1, "Sample rate out of range 72 .. 10000"); + R.rateMult = sr / (INTRATE / 1000); + break; + case 'W': + R.bandwidth = atoi(optarg); break; case 'L': R.lnaState = atoi(optarg); break; case 'G': - R.GRdB = atoi(optarg); + R.gRdB = atoi(optarg); + break; + case 'n': + if (strcasecmp(optarg, "RF") == 0 || strcasecmp(optarg, "FM") == 0) { + R.rfNotch = 1; + } else if (strcasecmp(optarg, "DAB") == 0) { + R.dabNotch = 1; + } else if (strcasecmp(optarg, "RSPduo-AM") == 0) { + R.rspDuoAmNotch = 1; + } else { + errx(-1, "Invalid notch selection"); + } break; #endif #ifdef WITH_SOAPY @@ -379,6 +409,8 @@ int main(int argc, char **argv) R.inmode = IN_SOAPY; inarg = optarg; break; +#endif +#if defined(WITH_SOAPY) || defined(WITH_SDRPLAY) case 'a': R.antenna = optarg; break; @@ -445,7 +477,7 @@ int main(int argc, char **argv) #endif #ifdef WITH_SDRPLAY case IN_SDRPLAY: - res = initSdrplay(); + res = initSdrplay(inarg); break; #endif #ifdef WITH_SOAPY @@ -532,7 +564,8 @@ int main(int argc, char **argv) #endif #ifdef WITH_SDRPLAY case IN_SDRPLAY: - res = runSdrplaySample(); + runSdrplaySample(); + res = runSdrplayClose(); break; #endif #ifdef WITH_SOAPY diff --git a/acarsdec.h b/acarsdec.h index c57bd78..5725c67 100644 --- a/acarsdec.h +++ b/acarsdec.h @@ -156,11 +156,17 @@ typedef struct { int ppm; int bias; unsigned int rateMult; +#ifdef WITH_SDRPLAY + int bandwidth; int lnaState; - int GRdB; + int gRdB; + int rfNotch; + int dabNotch; + int rspDuoAmNotch; +#endif unsigned int Fc, minFc, maxFc; -#ifdef WITH_SOAPY +#if defined(WITH_SOAPY) || defined(WITH_SDRPLAY) char *antenna; #endif } runtime_t; diff --git a/sdrplay.c b/sdrplay.c index 2b5f6e4..e385695 100644 --- a/sdrplay.c +++ b/sdrplay.c @@ -1,7 +1,8 @@ /* * Copyright (c) 2015 Thierry Leconte + * Copyright (c) 2025 Franco Venturi + * * - * * This code is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License version 2 * published by the Free Software Foundation. @@ -14,10 +15,6 @@ * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Taken the input variant from rtl.c, a variant for use with the - * sdrplay was created - * J van Katwijk, Lazy Chair Computing (J.vanKatwijk@gmail.com) */ #include @@ -26,175 +23,408 @@ #include #include #include +#include #include "acarsdec.h" #include "lib.h" -#include - -#warning "Untested - help wanted" +#include -#define SDRPLAY_MULT 170U // supports arbitrary SR between 2 and 10MSps -#define SDRPLAY_INRATE (INTRATE * SDRPLAY_MULT) +// choose 252 as the 12k (INTRATE) multiplier because 12k * 252 = 3024Msps +// (which is reasonable) +// the specific reason for 252 is that the SDRplay API RX callback size +// (numSamples) is 1008, which is an integer multiple of 252, and that is +// supposed to improve performance with acarsdec +#define SDRPLAY_MULT 252U #define ERRPFX "ERROR: SDRplay: " #define WARNPFX "WARNING: SDRplay: " -static int RSP1_Table[] = { 0, 24, 19, 43 }; - -static int RSP1A_Table[] = { 0, 6, 12, 18, 20, 26, 32, 38, 57, 62 }; - -static int RSP2_Table[] = { 0, 10, 15, 21, 24, 34, 39, 45, 64 }; +static unsigned int Fc; +static sdrplay_api_DeviceT device; -static int RSPduo_Table[] = { 0, 6, 12, 18, 20, 26, 32, 38, 57, 62 }; - -static int get_lnaGRdB(int hwVersion, int lnaState) +int initSdrplay(char *optarg) { - switch (hwVersion) { - case 1: - return RSP1_Table[lnaState]; + int r; + sdrplay_api_DeviceT devices[4]; + sdrplay_api_ErrT err; - case 2: - return RSP2_Table[lnaState]; + if (!optarg) + return 1; // cannot happen with getopt() - default: - return RSP1A_Table[lnaState]; + char *serialNumber = NULL; + int rspSequenceNumber = -1; + if (strlen(optarg) == 10 && strspn(optarg, "0123456789ABCDEF") == 10) { + serialNumber = optarg; + } else if (strlen(optarg) == 1 && strspn(optarg, "0123456789") == 1) { + rspSequenceNumber = atoi(optarg); + } else { + fprintf(stderr, ERRPFX "invalid RSP serial number or sequence number (0..3): %s\n", optarg); + return 2; } -} -// -unsigned int Fc; -int initSdrplay(void) -{ - int r; - char *argF; - int result; - uint32_t i; - uint deviceIndex, numofDevs; - mir_sdr_DeviceT devDesc[4]; - mir_sdr_ErrT err; + if (!R.rateMult) + R.rateMult = SDRPLAY_MULT; + unsigned int sr = INTRATE * R.rateMult; + int decimation = 1; + while (sr < 2000000 && decimation <= 32) { + sr *= 2; + decimation *= 2; + } - R.rateMult = SDRPLAY_MULT; + if (!R.bandwidth) { + unsigned int srbw = INTRATE * R.rateMult; + if (srbw < 300000) { R.bandwidth = 200; } + else if (srbw < 600000) { R.bandwidth = 300; } + else if (srbw < 1536000) { R.bandwidth = 600; } + else if (srbw < 5000000) { R.bandwidth = 1536; } + else if (srbw < 6000000) { R.bandwidth = 5000; } + else if (srbw < 7000000) { R.bandwidth = 6000; } + else if (srbw < 8000000) { R.bandwidth = 7000; } + else { R.bandwidth = 8000; } + } + if (!(R.bandwidth == 200 || + R.bandwidth == 300 || + R.bandwidth == 600 || + R.bandwidth == 1536 || + R.bandwidth == 5000 || + R.bandwidth == 6000 || + R.bandwidth == 7000 || + R.bandwidth == 8000)) { + fprintf(stderr, ERRPFX "invalid bandwidth (supported values: 200, 300, 600, 1536, 5000, 6000, 7000, 8000)\n"); + return 4; + } - if (!R.GRdB) - R.GRdB = -100; + if (!R.gRdB) + R.gRdB = -100; // AGC if (!R.lnaState) R.lnaState = 2; - Fc = find_centerfreq(R.minFc, R.maxFc, SDRPLAY_MULT); + Fc = find_centerfreq(R.minFc, R.maxFc, R.rateMult); if (Fc == 0) - return 1; + return 5; - r = channels_init_sdr(Fc, SDRPLAY_MULT, DMBUFSZ, 32768.0F); + r = channels_init_sdr(Fc, R.rateMult, 32768.0F); if (r) return r; - float ver; - result = mir_sdr_ApiVersion(&ver); - if (ver != MIR_SDR_API_VERSION) { - fprintf(stderr, ERRPFX "wrong api version %f %d\n", ver, result); + /* open SDRplay API and check version */ + err = sdrplay_api_Open(); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "Open failed: %s\n", sdrplay_api_GetErrorString(err)); return -1; } + float ver; + err = sdrplay_api_ApiVersion(&ver); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "ApiVersion failed: %s\n", sdrplay_api_GetErrorString(err)); + sdrplay_api_Close(); + return -2; + } + if (ver != SDRPLAY_API_VERSION) { + fprintf(stderr, ERRPFX "API version mismatch - expected=%.2f found=%.2f\n", SDRPLAY_API_VERSION, ver); + sdrplay_api_Close(); + return -3; + } - mir_sdr_GetDevices(devDesc, &numofDevs, (uint32_t)4); - if (numofDevs == 0) { - fprintf(stderr, ERRPFX "Sorry, no device found\n"); - return 2; + /* select device */ + err = sdrplay_api_LockDeviceApi(); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "LockDeviceApi failed: %s\n", sdrplay_api_GetErrorString(err)); + sdrplay_api_Close(); + return -4; + } + unsigned int ndevices = sizeof(devices) / sizeof(devices[0]); + err = sdrplay_api_GetDevices(devices, &ndevices, ndevices); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "GetDevices failed: %s\n", sdrplay_api_GetErrorString(err)); + sdrplay_api_UnlockDeviceApi(); + sdrplay_api_Close(); + return -5; + } + int deviceIndex = -1; + if (serialNumber != NULL) { + for (unsigned int i = 0; i < ndevices; i++) { + if (devices[i].valid && + (strcmp(devices[i].SerNo, serialNumber) == 0)) { + deviceIndex = i; + break; + } + } + } else if (rspSequenceNumber >= 0) { + if (ndevices > rspSequenceNumber) + deviceIndex = rspSequenceNumber; + } + if (deviceIndex == -1) { + fprintf(stderr, ERRPFX "RSP not found or not available\n"); + sdrplay_api_UnlockDeviceApi(); + sdrplay_api_Close(); + return -6; + } + device = devices[deviceIndex]; + + /* for RSPduo make sure single tuner mode is available */ + if (device.hwVer == SDRPLAY_RSPduo_ID) { + if ((device.rspDuoMode & sdrplay_api_RspDuoMode_Single_Tuner) != sdrplay_api_RspDuoMode_Single_Tuner) { + fprintf(stderr, ERRPFX "RSPduo single tuner mode not available\n"); + sdrplay_api_UnlockDeviceApi(); + sdrplay_api_Close(); + return -7; + } + device.rspDuoMode = sdrplay_api_RspDuoMode_Single_Tuner; + if (R.antenna != NULL) { + if (strcmp(R.antenna, "Tuner 1 50 ohm") == 0 || strcmp(R.antenna, "High Z") == 0) { + device.tuner = sdrplay_api_Tuner_A; + } else if (strcmp(R.antenna, "Tuner 2 50 ohm") == 0) { + device.tuner = sdrplay_api_Tuner_B; + } else { + device.tuner = sdrplay_api_Tuner_A; + } + } + device.rspDuoSampleFreq = 0; + } + + err = sdrplay_api_SelectDevice(&device); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "SelectDevice failed: %s\n", sdrplay_api_GetErrorString(err)); + sdrplay_api_UnlockDeviceApi(); + sdrplay_api_Close(); + return -8; + } + + err = sdrplay_api_UnlockDeviceApi(); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "UnlockDeviceApi failed: %s\n", sdrplay_api_GetErrorString(err)); + sdrplay_api_ReleaseDevice(&device); + sdrplay_api_Close(); + return -9; + } + + /* select device settings */ + sdrplay_api_DeviceParamsT *device_params; + err = sdrplay_api_GetDeviceParams(device.dev, &device_params); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "GetDeviceParams failed: %s\n", sdrplay_api_GetErrorString(err)); + sdrplay_api_ReleaseDevice(&device); + sdrplay_api_Close(); + return -10; + } + + device_params->devParams->mode = sdrplay_api_BULK; + + sdrplay_api_RxChannelParamsT *rx_channel_params = device_params->rxChannelA ; + device_params->devParams->fsFreq.fsHz = (double)sr; + rx_channel_params->ctrlParams.decimation.enable = decimation > 1; + rx_channel_params->ctrlParams.decimation.decimationFactor = decimation; + rx_channel_params->tunerParams.ifType = sdrplay_api_IF_Zero; + rx_channel_params->tunerParams.bwType = (sdrplay_api_Bw_MHzT)(R.bandwidth); + if (R.gRdB == -100) { + rx_channel_params->ctrlParams.agc.enable = sdrplay_api_AGC_100HZ; + } else { + rx_channel_params->ctrlParams.agc.enable = sdrplay_api_AGC_DISABLE; + rx_channel_params->tunerParams.gain.gRdB = R.gRdB; + } + rx_channel_params->tunerParams.gain.LNAstate = R.lnaState; + device_params->devParams->ppm = (double)(R.ppm); + rx_channel_params->tunerParams.rfFreq.rfHz = Fc; + if (R.antenna != NULL) { + int antennaOK = 0; + if (device.hwVer == SDRPLAY_RSP2_ID) { + if (strcmp(R.antenna, "Antenna A") == 0) { + antennaOK = 1; + rx_channel_params->rsp2TunerParams.antennaSel = sdrplay_api_Rsp2_ANTENNA_A; + rx_channel_params->rsp2TunerParams.amPortSel = sdrplay_api_Rsp2_AMPORT_2; + } else if (strcmp(R.antenna, "Antenna B") == 0) { + antennaOK = 1; + rx_channel_params->rsp2TunerParams.antennaSel = sdrplay_api_Rsp2_ANTENNA_B; + rx_channel_params->rsp2TunerParams.amPortSel = sdrplay_api_Rsp2_AMPORT_2; + } else if (strcmp(R.antenna, "Hi-Z") == 0) { + antennaOK = 1; + rx_channel_params->rsp2TunerParams.antennaSel = sdrplay_api_Rsp2_ANTENNA_A; + rx_channel_params->rsp2TunerParams.amPortSel = sdrplay_api_Rsp2_AMPORT_1; + } + } else if (device.hwVer == SDRPLAY_RSPduo_ID) { + if (strcmp(R.antenna, "High Z") == 0) { + antennaOK = 1; + rx_channel_params->rspDuoTunerParams.tuner1AmPortSel = sdrplay_api_RspDuo_AMPORT_1; + } else { + antennaOK = 1; + rx_channel_params->rspDuoTunerParams.tuner1AmPortSel = sdrplay_api_RspDuo_AMPORT_2; + } + } else if (device.hwVer == SDRPLAY_RSPdx_ID || device.hwVer == SDRPLAY_RSPdxR2_ID) { + if (strcmp(R.antenna, "Antenna A") == 0) { + antennaOK = 1; + device_params->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_A; + } else if (strcmp(R.antenna, "Antenna B") == 0) { + antennaOK = 1; + device_params->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_B; + } else if (strcmp(R.antenna, "Antenna C") == 0) { + antennaOK = 1; + device_params->devParams->rspDxParams.antennaSel = sdrplay_api_RspDx_ANTENNA_C; + } + } + if (!antennaOK) { + fprintf(stderr, ERRPFX "invalid antenna: %s\n", R.antenna); + sdrplay_api_ReleaseDevice(&device); + sdrplay_api_Close(); + return -11; + } + } + + if (R.bias) { + if (device.hwVer == SDRPLAY_RSP1A_ID || SDRPLAY_RSP1B_ID) { + rx_channel_params->rsp1aTunerParams.biasTEnable = R.bias; + } else if (device.hwVer == SDRPLAY_RSP2_ID) { + rx_channel_params->rsp2TunerParams.biasTEnable = R.bias; + } else if (device.hwVer == SDRPLAY_RSPduo_ID) { + rx_channel_params->rspDuoTunerParams.biasTEnable = R.bias; + } else if (device.hwVer == SDRPLAY_RSPdx_ID || device.hwVer == SDRPLAY_RSPdxR2_ID) { + device_params->devParams->rspDxParams.biasTEnable = R.bias; + } } - deviceIndex = 0; - int hwVersion = devDesc[deviceIndex].hwVer; - fprintf(stderr, "%s %s\n", devDesc[deviceIndex].DevNm, devDesc[deviceIndex].SerNo); - err = mir_sdr_SetDeviceIdx(deviceIndex); - if (err != mir_sdr_Success) { - fprintf(stderr, ERRPFX "Cannot start with device\n"); - return 1; + /* notch filters */ + if (device.hwVer == SDRPLAY_RSP1A_ID || SDRPLAY_RSP1B_ID) { + device_params->devParams->rsp1aParams.rfNotchEnable = R.rfNotch; + device_params->devParams->rsp1aParams.rfDabNotchEnable = R.dabNotch; + } else if (device.hwVer == SDRPLAY_RSP2_ID) { + rx_channel_params->rsp2TunerParams.rfNotchEnable = R.rfNotch; + } else if (device.hwVer == SDRPLAY_RSPduo_ID) { + rx_channel_params->rspDuoTunerParams.rfNotchEnable = R.rfNotch; + rx_channel_params->rspDuoTunerParams.rfDabNotchEnable = R.dabNotch; + rx_channel_params->rspDuoTunerParams.tuner1AmNotchEnable = R.rspDuoAmNotch; + } else if (device.hwVer == SDRPLAY_RSPdx_ID || device.hwVer == SDRPLAY_RSPdxR2_ID) { + device_params->devParams->rspDxParams.rfNotchEnable = R.rfNotch; + device_params->devParams->rspDxParams.rfDabNotchEnable = R.dabNotch; } - if (R.GRdB == -100) - fprintf(stderr, "SDRplay device selects freq %d and sets autogain\n", Fc); + if (R.gRdB == -100) + fprintf(stderr, "SDRplay device selects freq %d and sets autogain and LNA state %d\n", Fc, R.lnaState); else - fprintf(stderr, "SDRplay device selects freq %d and sets %d as gain reduction\n", - Fc, get_lnaGRdB(hwVersion, R.lnaState) + R.GRdB); + fprintf(stderr, "SDRplay device selects freq %d and sets IF gain reduction %d and LNA state %d\n", + Fc, R.gRdB, R.lnaState); + + return 0; +} + +static void sdrplayRXCallback(short *xi, + short *xq, + sdrplay_api_StreamCbParamsT *params, + unsigned int numSamples, + unsigned int reset, + void *cbContext); +void sdrplayEventCallback(sdrplay_api_EventT eventId, + sdrplay_api_TunerSelectT tuner, + sdrplay_api_EventParamsT *params, + void *cbContext); + +int runSdrplaySample(void) +{ + sdrplay_api_ErrT err; + + sdrplay_api_CallbackFnsT callbackFns = { + sdrplayRXCallback, + NULL, + sdrplayEventCallback + }; + + err = sdrplay_api_Init(device.dev, &callbackFns, NULL); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "Init failed: %s\n", sdrplay_api_GetErrorString(err)); + sdrplay_api_ReleaseDevice(&device); + sdrplay_api_Close(); + return -1; + } + + while (R.running) + sleep(2); + + err = sdrplay_api_Uninit(device.dev); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "Uninit failed: %s\n", sdrplay_api_GetErrorString(err)); + sdrplay_api_ReleaseDevice(&device); + sdrplay_api_Close(); + return -2; + } return 0; } -static unsigned int current_index = 0; -static void myStreamCallback(int16_t *xi, - int16_t *xq, - uint32_t firstSampleNum, - int32_t grChanged, - int32_t rfChanged, - int32_t fsChanged, - uint32_t numSamples, - uint32_t reset, - uint32_t hwRemoved, - void *cbContext) +static unsigned int nextSampleNum = 0xffffffff; + +static void sdrplayRXCallback(short *xi, + short *xq, + sdrplay_api_StreamCbParamsT *params, + unsigned int numSamples, + unsigned int reset, + void *cbContext) { - float complex phasors[SDRPLAY_MULT]; - unsigned int i, lim; + (void)reset; + (void)cbContext; + + /* check for dropped samples */ + if (nextSampleNum != 0xffffffff && params->firstSampleNum != nextSampleNum) { + unsigned int dropped_samples; + if (nextSampleNum < params->firstSampleNum) { + dropped_samples = params->firstSampleNum - nextSampleNum; + } else { + dropped_samples = UINT_MAX - (params->firstSampleNum - nextSampleNum) + 1; + } + fprintf(stderr, WARNPFX "dropped %d samples\n", dropped_samples); + } + nextSampleNum = params->firstSampleNum + numSamples; + + float complex phasors[R.rateMult]; + unsigned int i, j, lim; + j = 0; while (numSamples) { - lim = numSamples < SDRPLAY_MULT ? numSamples : SDRPLAY_MULT; // mult-sized chunks - for (i = 0; i < lim; i++) { - float r = ((float)(xi[i])); - float g = ((float)(xq[i])); + /* mult-sized chunks */ + lim = numSamples < R.rateMult ? numSamples : R.rateMult; + for (i = 0; i < lim; i++, j++) { + float r = ((float)(xi[j])); + float g = ((float)(xq[j])); phasors[i] = r + g * I; - channels_mix_phasors(phasors, lim, SDRPLAY_MULT); } + channels_mix_phasors(phasors, lim, R.rateMult); numSamples -= lim; } } -static void myGainChangeCallback(uint32_t gRdB, - uint32_t lnaGRdB, - void *cbContext) +void sdrplayEventCallback(sdrplay_api_EventT eventId, + sdrplay_api_TunerSelectT tuner, + sdrplay_api_EventParamsT *params, + void *cbContext) { - (void)gRdB; - (void)lnaGRdB; (void)cbContext; + + if (eventId == sdrplay_api_PowerOverloadChange) { + switch (params->powerOverloadParams.powerOverloadChangeType) { + case sdrplay_api_Overload_Detected: + fprintf(stderr, WARNPFX "power overload detected event\n"); + break; + case sdrplay_api_Overload_Corrected: + fprintf(stderr, WARNPFX "power overload correct event\n"); + break; + } + sdrplay_api_Update(device.dev, tuner, sdrplay_api_Update_Ctrl_OverloadMsgAck, sdrplay_api_Update_Ext1_None); + } + return; } -int runSdrplaySample(void) +int runSdrplayClose(void) { - int result; - int gRdBSystem = 0; - int samplesPerPacket; - int MHz_1 = 1000000; - int localGRdB = (20 <= R.GRdB) && (R.GRdB <= 59) ? R.GRdB : 20; - - result = mir_sdr_StreamInit(&localGRdB, - ((double)(SDRPLAY_INRATE)) / MHz_1, - ((double)Fc) / MHz_1, - mir_sdr_BW_1_536, - mir_sdr_IF_Zero, - R.lnaState, - &gRdBSystem, - mir_sdr_USE_RSP_SET_GR, - &samplesPerPacket, - (mir_sdr_StreamCallback_t)myStreamCallback, - (mir_sdr_GainChangeCallback_t)myGainChangeCallback, - NULL); - - if (result != mir_sdr_Success) { - fprintf(stderr, ERRPFX "Error %d on streamInit\n", result); + sdrplay_api_ErrT err; + + err = sdrplay_api_ReleaseDevice(&device); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "ReleaseDevice failed: %s\n", sdrplay_api_GetErrorString(err)); + sdrplay_api_Close(); return -1; } - if (R.GRdB == -100) { - result = mir_sdr_AgcControl(mir_sdr_AGC_100HZ, - -30, 0, 0, 0, 0, R.lnaState); - if (result != mir_sdr_Success) - fprintf(stderr, ERRPFX "Error %d on AgcControl\n", result); + err = sdrplay_api_Close(); + if (err != sdrplay_api_Success) { + fprintf(stderr, ERRPFX "Close failed: %s\n", sdrplay_api_GetErrorString(err)); + return -2; } - - mir_sdr_SetPpm((float)R.ppm); - mir_sdr_SetDcMode(4, 1); - mir_sdr_SetDcTrackTime(63); - // - mir_sdr_DCoffsetIQimbalanceControl(0, 1); - while (R.running) - sleep(2); - - mir_sdr_ReleaseDeviceIdx(); return 0; } diff --git a/sdrplay.h b/sdrplay.h index bfca51b..ef08fd7 100644 --- a/sdrplay.h +++ b/sdrplay.h @@ -1,7 +1,8 @@ #ifndef sdrplay_h #define sdrplay_h -int initSdrplay(void); +int initSdrplay(char *optarg); int runSdrplaySample(void); +int runSdrplayClose(void); #endif /* sdrplay_h */