Some great results thanks to sdrplay support over the last few weeks. Using the sample v3 api code for windows I added code to dump both tuner IQ streams to stdout. An earlier version of the play_sdr command line app I'd hacked together for my RSP2s under Linux featured antenna switching, tuning and frequency hopping. Taking the tuning bits of that code and porting it to windows enabled basic testing with the duo to check how coherent both tuners are. - in a word, excellent.
Heres a video showing the duo tuning via a windows laptop streaming IQ samples (via netcat) to a Linux server running baudline.
https://urlme.net/dl/sdrduo-dualtuningtest.mp4
And a still capture

The main learning with the API was the correct initialisation sequence to use for dual tuner use and updating the example code to actually output samples. The relevant example code expansion is below. Its not a complete example and needs incorporating/rewriting for the final requirements of your application.
Code: Select all
// stream A writes tuner 1 iq, stream B writes tuner 2 IQ and dumps output
void StreamACallback(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext)
{
if (reset)
fprintf(stderr,"sdrplay_api_StreamACallback: numSamples=%d\n", numSamples);
// Process stream callback data here
int i = 0;
int j = 0;
// iiqqxxxx
for (i = 0; i < numSamples; i++) {
dualout[j++]=xi[i]; // add Tuner A data
dualout[j++]=xq[i];
j++; // skip Tuner B data
j++;
}
return;
}
void StreamBCallback(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext)
{
if (reset)
fprintf(stderr,"sdrplay_api_StreamBCallback: numSamples=%d\n", numSamples);
// Process stream callback data here - this callback will only be used in dual tuner mode
int i = 0;
int j = 0;
// xxxxIIQQ
for (i = 0; i < numSamples; i++) {
j++; // skip tuner A data
j++;
dualout[j++]=xi[i]; // add tuner B data
dualout[j++]=xq[i];
}
// iiqqIIQQ
fwrite(dualout, sizeof(short), j, stdout); // 2 pairs, ignore short writes
return;
}
In the example code find the section related to the duo and modify to:-
// If chosen device is an RSPduo, assign additional fields
if (chosenDevice->hwVer == SDRPLAY_RSPduo_ID)
{
chosenDevice->rspDuoMode=sdrplay_api_RspDuoMode_Dual_Tuner;
chosenDevice->rspDuoSampleFreq=6000000.0;
chosenDevice->tuner = sdrplay_api_Tuner_Both; //Both;
fprintf(stderr,"DUO Dual Dev%d: selected rspDuoMode=0x%.2x tuner=0x%.2x\n", chosenIdx, chosenDevice->rspDuoMode, chosenDevice->tuner);
}
....
And configure the tuner paramters
// Configure tuner parameters (depends on selected Tuner which set of parameters to use)
chosenDevice->tuner = sdrplay_api_Tuner_A;
deviceParams->rxChannelA->tunerParams.rfFreq.rfHz = frequency1;
deviceParams->devParams->fsFreq.fsHz = 6000000.0;
deviceParams->rxChannelA->tunerParams.bwType = sdrplay_api_BW_1_536;
deviceParams->rxChannelA->tunerParams.ifType = sdrplay_api_IF_1_620;
deviceParams->rxChannelA->tunerParams.gain.gRdB = somegain; eg 45
deviceParams->rxChannelA->tunerParams.gain.LNAstate = anicelnavalue; eg 5
deviceParams->rxChannelA->ctrlParams.agc.enable = sdrplay_api_AGC_DISABLE;
chParams = deviceParams->rxChannelA;
// Assign callback functions to be passed to sdrplay_api_Init()
cbFns.StreamACbFn = StreamACallback;
cbFns.StreamBCbFn = StreamBCallback;
cbFns.EventCbFn = EventCallback;
fprintf(stderr,"Debug A\n");
// Now we're ready to start by calling the initialisation function
// This will configure the device and start streaming
if ((err = sdrplay_api_Init(chosenDevice->dev, &cbFns, NULL)) != sdrplay_api_Success)
...
In main - malloc e.g 8192 bytes for the dualout buffer making a rather bad assumption it
never exceeds that.