2017-01-02 21:07:43 -05:00
// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+
2015-09-13 22:18:29 -04:00
# include "SoapySDRThread.h"
# include "CubicSDRDefs.h"
# include <vector>
# include "CubicSDR.h"
# include <string>
2017-05-19 20:01:07 +02:00
# include <algorithm>
2016-01-02 21:42:35 -05:00
# include <SoapySDR/Logger.h>
2015-09-13 22:18:29 -04:00
2015-12-04 22:10:51 -05:00
SDRThread : : SDRThread ( ) : IOThread ( ) , buffers ( " SDRThreadBuffers " ) {
2015-10-03 21:35:11 -04:00
device = NULL ;
deviceConfig . store ( NULL ) ;
deviceInfo . store ( NULL ) ;
2015-10-21 16:56:32 -04:00
sampleRate . store ( DEFAULT_SAMPLE_RATE ) ;
2015-10-03 21:35:11 -04:00
frequency . store ( 0 ) ;
offset . store ( 0 ) ;
ppm . store ( 0 ) ;
numElems . store ( 0 ) ;
rate_changed . store ( false ) ;
freq_changed . store ( false ) ;
offset_changed . store ( false ) ;
ppm_changed . store ( false ) ;
device_changed . store ( false ) ;
hasPPM . store ( false ) ;
hasHardwareDC . store ( false ) ;
2015-10-14 00:54:48 -04:00
numChannels . store ( 8 ) ;
2015-10-27 01:56:49 -04:00
agc_mode . store ( true ) ;
agc_mode_changed . store ( false ) ;
gain_value_changed . store ( false ) ;
2015-11-03 21:06:22 -05:00
setting_value_changed . store ( false ) ;
2016-01-07 00:35:02 -05:00
frequency_lock_init . store ( false ) ;
frequency_locked . store ( false ) ;
lock_freq . store ( 0 ) ;
2016-02-15 15:07:57 -05:00
iq_swap . store ( false ) ;
2015-09-13 22:18:29 -04:00
}
SDRThread : : ~ SDRThread ( ) {
2015-10-03 21:35:11 -04:00
2015-09-13 22:18:29 -04:00
}
2015-11-04 02:04:52 -05:00
SoapySDR : : Kwargs SDRThread : : combineArgs ( SoapySDR : : Kwargs a , SoapySDR : : Kwargs b ) {
SoapySDR : : Kwargs c ;
SoapySDR : : Kwargs : : iterator i ;
for ( i = a . begin ( ) ; i ! = a . end ( ) ; i + + ) {
c [ i - > first ] = i - > second ;
}
for ( i = b . begin ( ) ; i ! = b . end ( ) ; i + + ) {
c [ i - > first ] = i - > second ;
}
return c ;
}
2016-07-24 11:59:59 -04:00
bool SDRThread : : init ( ) {
2016-01-26 21:49:42 -05:00
//#warning Debug On
2016-01-02 21:42:35 -05:00
// SoapySDR_setLogLevel(SOAPY_SDR_DEBUG);
2015-10-03 21:35:11 -04:00
SDRDeviceInfo * devInfo = deviceInfo . load ( ) ;
deviceConfig . store ( wxGetApp ( ) . getConfig ( ) - > getDevice ( devInfo - > getDeviceId ( ) ) ) ;
DeviceConfig * devConfig = deviceConfig . load ( ) ;
2015-09-13 22:18:29 -04:00
2015-10-03 21:35:11 -04:00
ppm . store ( devConfig - > getPPM ( ) ) ;
2015-10-23 02:53:51 -04:00
ppm_changed . store ( true ) ;
2015-10-03 21:35:11 -04:00
std : : string driverName = devInfo - > getDriver ( ) ;
2015-09-13 22:18:29 -04:00
2015-10-03 21:35:11 -04:00
offset = devConfig - > getOffset ( ) ;
2015-09-13 22:18:29 -04:00
2015-10-03 21:35:11 -04:00
SoapySDR : : Kwargs args = devInfo - > getDeviceArgs ( ) ;
2015-09-26 01:41:30 -04:00
2015-10-05 02:21:08 -04:00
wxGetApp ( ) . sdrEnumThreadNotify ( SDREnumerator : : SDR_ENUM_MESSAGE , std : : string ( " Initializing device. " ) ) ;
2016-01-26 21:49:42 -05:00
2016-01-31 15:11:54 -05:00
device = devInfo - > getSoapyDevice ( ) ;
2016-01-26 21:49:42 -05:00
2015-12-06 00:32:32 -05:00
SoapySDR : : Kwargs currentStreamArgs = combineArgs ( devInfo - > getStreamArgs ( ) , streamArgs ) ;
2016-07-24 11:59:59 -04:00
std : : string streamExceptionStr ( " " ) ;
try {
stream = device - > setupStream ( SOAPY_SDR_RX , " CF32 " , std : : vector < size_t > ( ) , currentStreamArgs ) ;
} catch ( exception e ) {
streamExceptionStr = e . what ( ) ;
}
if ( ! stream ) {
wxGetApp ( ) . sdrThreadNotify ( SDRThread : : SDR_THREAD_FAILED , std : : string ( " Stream setup failed, stream is null. " ) + streamExceptionStr ) ;
std : : cout < < " Stream setup failed, stream is null. " < < streamExceptionStr < < std : : endl ;
return false ;
}
2016-01-26 21:49:42 -05:00
int streamMTU = device - > getStreamMTU ( stream ) ;
mtuElems . store ( streamMTU ) ;
std : : cout < < " Stream MTU: " < < mtuElems . load ( ) < < std : : endl < < std : : flush ;
2015-12-06 00:32:32 -05:00
deviceInfo . load ( ) - > setStreamArgs ( currentStreamArgs ) ;
deviceConfig . load ( ) - > setStreamOpts ( currentStreamArgs ) ;
2015-09-30 23:45:06 -04:00
2015-10-05 02:21:08 -04:00
wxGetApp ( ) . sdrEnumThreadNotify ( SDREnumerator : : SDR_ENUM_MESSAGE , std : : string ( " Activating stream. " ) ) ;
2015-09-13 22:18:29 -04:00
device - > setSampleRate ( SOAPY_SDR_RX , 0 , sampleRate . load ( ) ) ;
2016-07-22 19:24:20 -04:00
// TODO: explore bandwidth setting option to see if this is necessary for others
2016-07-22 19:43:22 -04:00
if ( device - > getDriverKey ( ) = = " bladeRF " ) {
2016-07-22 19:24:20 -04:00
device - > setBandwidth ( SOAPY_SDR_RX , 0 , sampleRate . load ( ) ) ;
}
2015-09-13 22:18:29 -04:00
device - > setFrequency ( SOAPY_SDR_RX , 0 , " RF " , frequency - offset . load ( ) ) ;
2015-10-20 01:54:20 -04:00
device - > activateStream ( stream ) ;
2016-01-31 15:11:54 -05:00
if ( devInfo - > hasCORR ( SOAPY_SDR_RX , 0 ) ) {
2015-10-05 02:21:08 -04:00
hasPPM . store ( true ) ;
device - > setFrequency ( SOAPY_SDR_RX , 0 , " CORR " , ppm . load ( ) ) ;
} else {
hasPPM . store ( false ) ;
}
2016-01-31 15:11:54 -05:00
if ( device - > hasDCOffsetMode ( SOAPY_SDR_RX , 0 ) ) {
2015-10-05 02:21:08 -04:00
hasHardwareDC . store ( true ) ;
2015-10-17 16:17:12 -04:00
// wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Found hardware DC offset correction support, internal disabled."));
2016-01-31 15:11:54 -05:00
device - > setDCOffsetMode ( SOAPY_SDR_RX , 0 , true ) ;
2015-10-05 02:21:08 -04:00
} else {
hasHardwareDC . store ( false ) ;
2015-09-26 01:41:30 -04:00
}
2015-10-23 02:53:51 -04:00
2015-10-27 01:56:49 -04:00
device - > setGainMode ( SOAPY_SDR_RX , 0 , agc_mode . load ( ) ) ;
2015-09-13 22:18:29 -04:00
2015-10-14 00:54:48 -04:00
numChannels . store ( getOptimalChannelCount ( sampleRate . load ( ) ) ) ;
numElems . store ( getOptimalElementCount ( sampleRate . load ( ) , 30 ) ) ;
2016-01-26 21:49:42 -05:00
if ( ! mtuElems . load ( ) ) {
mtuElems . store ( numElems . load ( ) ) ;
}
2017-05-19 20:01:07 +02:00
2016-01-26 21:49:42 -05:00
overflowBuffer . data . resize ( mtuElems . load ( ) ) ;
2015-09-22 21:03:23 -04:00
2016-01-26 21:49:42 -05:00
buffs [ 0 ] = malloc ( mtuElems . load ( ) * 4 * sizeof ( float ) ) ;
numOverflow = 0 ;
2015-11-03 21:06:22 -05:00
SoapySDR : : ArgInfoList settingsInfo = device - > getSettingInfo ( ) ;
SoapySDR : : ArgInfoList : : const_iterator settings_i ;
if ( ! setting_value_changed . load ( ) ) {
settings . erase ( settings . begin ( ) , settings . end ( ) ) ;
settingChanged . erase ( settingChanged . begin ( ) , settingChanged . end ( ) ) ;
}
2016-06-02 23:56:31 +02:00
{ //enter scoped-lock
std : : lock_guard < std : : mutex > lock ( setting_busy ) ;
for ( settings_i = settingsInfo . begin ( ) ; settings_i ! = settingsInfo . end ( ) ; settings_i + + ) {
SoapySDR : : ArgInfo setting = ( * settings_i ) ;
if ( ( settingChanged . find ( setting . key ) ! = settingChanged . end ( ) ) & & ( settings . find ( setting . key ) ! = settings . end ( ) ) ) {
device - > writeSetting ( setting . key , settings [ setting . key ] ) ;
settingChanged [ setting . key ] = false ;
} else {
settings [ setting . key ] = device - > readSetting ( setting . key ) ;
settingChanged [ setting . key ] = false ;
}
2015-11-03 21:06:22 -05:00
}
2016-06-02 23:56:31 +02:00
setting_value_changed . store ( false ) ;
2015-12-06 00:32:32 -05:00
2016-06-02 23:56:31 +02:00
} //leave lock guard scope
2015-11-03 21:06:22 -05:00
2016-02-01 20:30:48 -05:00
updateSettings ( ) ;
2015-11-03 21:06:22 -05:00
wxGetApp ( ) . sdrThreadNotify ( SDRThread : : SDR_THREAD_INITIALIZED , std : : string ( " Device Initialized. " ) ) ;
2016-07-24 11:59:59 -04:00
return true ;
2015-10-03 21:35:11 -04:00
}
void SDRThread : : deinit ( ) {
device - > deactivateStream ( stream ) ;
device - > closeStream ( stream ) ;
free ( buffs [ 0 ] ) ;
}
2015-09-13 22:18:29 -04:00
2017-05-19 20:01:07 +02:00
void SDRThread : : assureBufferMinSize ( SDRThreadIQData * dataOut , size_t minSize ) {
if ( dataOut - > data . size ( ) < minSize ) {
dataOut - > data . resize ( minSize ) ;
}
}
//Called in an infinite loop, read SaopySDR device to build
// a 'this.numElems' sized batch of samples (SDRThreadIQData) and push it into iqDataOutQueue.
2015-10-03 21:35:11 -04:00
void SDRThread : : readStream ( SDRThreadIQDataQueue * iqDataOutQueue ) {
2015-09-13 22:18:29 -04:00
int flags ;
long long timeNs ;
2015-10-03 21:35:11 -04:00
int n_read = 0 ;
2016-01-26 21:49:42 -05:00
int nElems = numElems . load ( ) ;
int mtElems = mtuElems . load ( ) ;
2017-05-19 20:01:07 +02:00
//0. Retreive a new batch
SDRThreadIQData * dataOut = buffers . getBuffer ( ) ;
//1.If overflow occured on the previous readStream(), transfer it in dataOut directly.
//Take care of the iq_swap option.
2016-01-26 21:49:42 -05:00
if ( numOverflow > 0 ) {
2017-05-19 20:01:07 +02:00
int n_overflow = std : : min ( numOverflow , nElems ) ;
assureBufferMinSize ( dataOut , n_overflow ) ;
: : memcpy ( & dataOut - > data [ 0 ] , & overflowBuffer . data [ 0 ] , n_overflow * sizeof ( liquid_float_complex ) ) ;
2016-01-26 21:49:42 -05:00
n_read = n_overflow ;
2017-05-19 20:01:07 +02:00
numOverflow = std : : min ( 0 , numOverflow - n_overflow ) ;
// std::cout << "SDRThread::readStream() 1.1 overflowBuffer not empty, collect the remaining " << n_overflow << " samples in it..." << std::endl;
2016-01-26 21:49:42 -05:00
2017-05-19 20:01:07 +02:00
if ( numOverflow > 0 ) { // still some left, shift the remaining samples to the begining..
: : memmove ( & overflowBuffer . data [ 0 ] , & overflowBuffer . data [ n_overflow ] , numOverflow * sizeof ( liquid_float_complex ) ) ;
std : : cout < < " SDRThread::readStream() 1.2 overflowBuffer still not empty, compact the remaining " < < numOverflow < < " samples in it... " < < std : : endl ;
2016-01-26 21:49:42 -05:00
}
2017-05-19 20:01:07 +02:00
} //end if numOverflow > 0
2016-01-26 21:49:42 -05:00
2017-05-19 20:01:07 +02:00
//2. attempt readStream() at most nElems, by mtElems-sized chunks, append in dataOut->data directly.
2016-06-28 21:04:52 +02:00
while ( n_read < nElems & & ! stopping ) {
2017-05-19 20:01:07 +02:00
//Whatever the number of remaining samples needed to reach nElems, we always try to read a mtElems-size chunk,
//from which SoapySDR effectively returns n_stream_read.
2016-01-26 21:49:42 -05:00
int n_stream_read = device - > readStream ( stream , buffs , mtElems , flags , timeNs ) ;
2016-07-05 21:43:45 +02:00
//if the n_stream_read <= 0, bail out from reading.
2017-01-21 11:26:51 +01:00
if ( n_stream_read = = 0 ) {
2017-05-19 20:01:07 +02:00
std : : cout < < " SDRThread::readStream(): 2. SoapySDR read blocking... " < < std : : endl ;
2017-01-21 11:26:51 +01:00
break ;
}
else if ( n_stream_read < 0 ) {
2017-05-19 20:01:07 +02:00
std : : cout < < " SDRThread::readStream(): 2. SoapySDR read failed with code: " < < n_stream_read < < std : : endl ;
2016-07-05 21:43:45 +02:00
break ;
}
2017-05-19 20:01:07 +02:00
//sucess read beyond nElems, so with overflow:
2016-01-26 21:49:42 -05:00
if ( ( n_read + n_stream_read ) > nElems ) {
2017-03-08 22:52:20 +01:00
2017-05-19 20:01:07 +02:00
//n_requested is the exact number to reach nElems.
//note: setting n_requested = n_stream_read;
//lead to push the whole n_stream_read, so no overflow management occurs,
//so dataOut->data can exess nElems by at most mtElems.
//TODO: doesn't change CubicSDR behaviour, so why not ?
int n_requested = nElems - n_read ;
//Copy at most n_requested CF32 into .data liquid_float_complex,
2017-03-08 22:52:20 +01:00
//starting at n_read position.
2017-03-10 19:12:54 +01:00
//inspired from SoapyRTLSDR code, this mysterious void** is indeed an array of CF32(real/imag) samples, indeed an array of
//float with the following layout [sample 1 real part , sample 1 imag part, sample 2 real part , sample 2 imag part,sample 3 real part , sample 3 imag part,...etc]
//Since there is indeed no garantee that sizeof(liquid_float_complex) = 2 * sizeof (float)
//nor that the Re/Im layout of fields matches the float array order, assign liquid_float_complex field by field.
2017-03-08 22:52:20 +01:00
float * pp = ( float * ) buffs [ 0 ] ;
2017-05-19 20:01:07 +02:00
assureBufferMinSize ( dataOut , n_read + n_requested ) ;
if ( iq_swap . load ( ) ) {
for ( int i = 0 ; i < n_requested ; i + + ) {
dataOut - > data [ n_read + i ] . imag = pp [ 2 * i ] ;
dataOut - > data [ n_read + i ] . real = pp [ 2 * i + 1 ] ;
}
} else {
for ( int i = 0 ; i < n_requested ; i + + ) {
dataOut - > data [ n_read + i ] . real = pp [ 2 * i ] ;
dataOut - > data [ n_read + i ] . imag = pp [ 2 * i + 1 ] ;
}
}
2017-03-08 22:52:20 +01:00
2017-05-19 20:01:07 +02:00
//shift of n_requested samples, each one made of 2 floats...
2017-03-08 22:52:20 +01:00
pp + = n_requested * 2 ;
2017-05-19 20:01:07 +02:00
//numNewOverflow are in exess, they have to be added in the existing overflowBuffer.
int numNewOverflow = n_stream_read - n_requested ;
2017-03-08 22:52:20 +01:00
//so push the remainder samples to overflowBuffer:
2017-05-19 20:01:07 +02:00
if ( numNewOverflow > 0 ) {
// std::cout << "SDRThread::readStream(): 2. SoapySDR read make nElems overflow by " << numNewOverflow << " samples..." << std::endl;
}
assureBufferMinSize ( & overflowBuffer , numOverflow + numNewOverflow ) ;
if ( iq_swap . load ( ) ) {
for ( int i = 0 ; i < numNewOverflow ; i + + ) {
overflowBuffer . data [ numOverflow + i ] . imag = pp [ 2 * i ] ;
overflowBuffer . data [ numOverflow + i ] . real = pp [ 2 * i + 1 ] ;
}
}
else {
for ( int i = 0 ; i < numNewOverflow ; i + + ) {
overflowBuffer . data [ numOverflow + i ] . real = pp [ 2 * i ] ;
overflowBuffer . data [ numOverflow + i ] . imag = pp [ 2 * i + 1 ] ;
}
}
numOverflow + = numNewOverflow ;
2016-01-26 21:49:42 -05:00
n_read + = n_requested ;
2017-05-19 20:01:07 +02:00
} else if ( n_stream_read > 0 ) { // no overflow, read the whole n_stream_read.
2017-03-08 22:52:20 +01:00
float * pp = ( float * ) buffs [ 0 ] ;
2017-05-19 20:01:07 +02:00
assureBufferMinSize ( dataOut , n_read + n_stream_read ) ;
if ( iq_swap . load ( ) ) {
for ( int i = 0 ; i < n_stream_read ; i + + ) {
dataOut - > data [ n_read + i ] . imag = pp [ 2 * i ] ;
dataOut - > data [ n_read + i ] . real = pp [ 2 * i + 1 ] ;
}
}
else {
for ( int i = 0 ; i < n_stream_read ; i + + ) {
dataOut - > data [ n_read + i ] . real = pp [ 2 * i ] ;
dataOut - > data [ n_read + i ] . imag = pp [ 2 * i + 1 ] ;
}
}
2017-03-08 22:52:20 +01:00
2015-10-03 21:35:11 -04:00
n_read + = n_stream_read ;
} else {
break ;
}
2017-01-21 11:26:51 +01:00
} //end while
2015-10-03 21:35:11 -04:00
2017-05-19 20:01:07 +02:00
//3. At that point, dataOut contains nElems (or less if a read has return an error), try to post in queue, else discard.
2016-07-06 21:23:59 +02:00
if ( n_read > 0 & & ! stopping & & ! iqDataOutQueue - > full ( ) ) {
2015-10-15 01:35:03 -04:00
2017-05-19 20:01:07 +02:00
//clamp result:
dataOut - > data . resize ( n_read ) ;
2015-10-14 00:54:48 -04:00
dataOut - > frequency = frequency . load ( ) ;
2015-10-03 21:35:11 -04:00
dataOut - > sampleRate = sampleRate . load ( ) ;
2015-10-14 00:54:48 -04:00
dataOut - > dcCorrected = hasHardwareDC . load ( ) ;
dataOut - > numChannels = numChannels . load ( ) ;
2015-10-03 21:35:11 -04:00
2017-02-09 19:12:12 +01:00
if ( ! iqDataOutQueue - > try_push ( dataOut ) ) {
2016-07-06 21:23:59 +02:00
//The rest of the system saturates,
//finally the push didn't suceeded, recycle dataOut immediatly.
dataOut - > setRefCount ( 0 ) ;
2017-05-19 20:01:07 +02:00
std : : cout < < " SDRThread::readStream(): 3.2 iqDataOutQueue output queue is full, discard processing of the batch... " < < std : : endl ;
2016-07-06 21:23:59 +02:00
//saturation, let a chance to the other threads to consume the existing samples
std : : this_thread : : yield ( ) ;
}
2017-05-19 20:01:07 +02:00
}
else {
dataOut - > setRefCount ( 0 ) ;
std : : cout < < " SDRThread::readStream(): 3.1 iqDataOutQueue output queue is full, discard processing of the batch... " < < std : : endl ;
}
2015-10-03 21:35:11 -04:00
}
2015-09-13 22:18:29 -04:00
2015-10-03 21:35:11 -04:00
void SDRThread : : readLoop ( ) {
2016-06-01 19:42:11 +02:00
SDRThreadIQDataQueue * iqDataOutQueue = static_cast < SDRThreadIQDataQueue * > ( getOutputQueue ( " IQDataOutput " ) ) ;
2015-10-03 21:35:11 -04:00
if ( iqDataOutQueue = = NULL ) {
return ;
}
2015-10-27 01:56:49 -04:00
updateGains ( ) ;
2016-06-28 21:04:52 +02:00
while ( ! stopping . load ( ) ) {
2015-11-03 21:06:22 -05:00
updateSettings ( ) ;
2015-10-03 21:35:11 -04:00
readStream ( iqDataOutQueue ) ;
2015-09-13 22:18:29 -04:00
}
2015-11-03 21:06:22 -05:00
2015-09-14 20:31:39 -04:00
buffers . purge ( ) ;
2015-10-03 21:35:11 -04:00
}
2015-10-27 01:56:49 -04:00
void SDRThread : : updateGains ( ) {
SDRDeviceInfo * devInfo = deviceInfo . load ( ) ;
gainValues . erase ( gainValues . begin ( ) , gainValues . end ( ) ) ;
gainChanged . erase ( gainChanged . begin ( ) , gainChanged . end ( ) ) ;
2016-01-31 15:11:54 -05:00
SDRRangeMap gains = devInfo - > getGains ( SOAPY_SDR_RX , 0 ) ;
for ( SDRRangeMap : : iterator gi = gains . begin ( ) ; gi ! = gains . end ( ) ; gi + + ) {
gainValues [ gi - > first ] = device - > getGain ( SOAPY_SDR_RX , 0 , gi - > first ) ;
gainChanged [ gi - > first ] = false ;
2015-10-27 01:56:49 -04:00
}
gain_value_changed . store ( false ) ;
}
2015-11-03 21:06:22 -05:00
void SDRThread : : updateSettings ( ) {
2016-02-02 19:27:08 -05:00
bool doUpdate = false ;
2016-07-24 11:59:59 -04:00
if ( ! stream ) {
return ;
}
2015-11-03 21:06:22 -05:00
if ( offset_changed . load ( ) ) {
if ( ! freq_changed . load ( ) ) {
frequency . store ( frequency . load ( ) ) ;
freq_changed . store ( true ) ;
}
offset_changed . store ( false ) ;
}
if ( rate_changed . load ( ) ) {
device - > setSampleRate ( SOAPY_SDR_RX , 0 , sampleRate . load ( ) ) ;
2016-07-22 19:24:20 -04:00
// TODO: explore bandwidth setting option to see if this is necessary for others
2016-07-22 19:43:22 -04:00
if ( device - > getDriverKey ( ) = = " bladeRF " ) {
2016-07-22 19:24:20 -04:00
device - > setBandwidth ( SOAPY_SDR_RX , 0 , sampleRate . load ( ) ) ;
}
2015-11-03 21:06:22 -05:00
sampleRate . store ( device - > getSampleRate ( SOAPY_SDR_RX , 0 ) ) ;
numChannels . store ( getOptimalChannelCount ( sampleRate . load ( ) ) ) ;
numElems . store ( getOptimalElementCount ( sampleRate . load ( ) , 60 ) ) ;
2016-01-26 21:49:42 -05:00
int streamMTU = device - > getStreamMTU ( stream ) ;
mtuElems . store ( streamMTU ) ;
if ( ! mtuElems . load ( ) ) {
mtuElems . store ( numElems . load ( ) ) ;
}
2017-05-19 20:01:07 +02:00
2016-01-26 21:49:42 -05:00
overflowBuffer . data . resize ( mtuElems . load ( ) ) ;
2015-11-03 21:06:22 -05:00
free ( buffs [ 0 ] ) ;
2016-01-26 21:49:42 -05:00
buffs [ 0 ] = malloc ( mtuElems . load ( ) * 4 * sizeof ( float ) ) ;
numOverflow = 0 ;
2015-11-03 21:06:22 -05:00
rate_changed . store ( false ) ;
2016-02-02 19:27:08 -05:00
doUpdate = true ;
2015-11-03 21:06:22 -05:00
}
if ( ppm_changed . load ( ) & & hasPPM . load ( ) ) {
device - > setFrequency ( SOAPY_SDR_RX , 0 , " CORR " , ppm . load ( ) ) ;
ppm_changed . store ( false ) ;
}
if ( freq_changed . load ( ) ) {
2016-01-07 00:35:02 -05:00
if ( frequency_locked . load ( ) & & ! frequency_lock_init . load ( ) ) {
device - > setFrequency ( SOAPY_SDR_RX , 0 , " RF " , lock_freq . load ( ) ) ;
frequency_lock_init . store ( true ) ;
} else if ( ! frequency_locked . load ( ) ) {
device - > setFrequency ( SOAPY_SDR_RX , 0 , " RF " , frequency . load ( ) - offset . load ( ) ) ;
}
2015-11-03 21:06:22 -05:00
freq_changed . store ( false ) ;
}
2016-01-04 00:56:18 -05:00
// double devFreq = device->getFrequency(SOAPY_SDR_RX,0);
// if (((long long)devFreq + offset.load()) != frequency.load()) {
// wxGetApp().setFrequency((long long)devFreq + offset.load());
// }
2016-01-02 21:42:35 -05:00
2015-11-03 21:06:22 -05:00
if ( agc_mode_changed . load ( ) ) {
2016-01-31 15:11:54 -05:00
device - > setGainMode ( SOAPY_SDR_RX , 0 , agc_mode . load ( ) ) ;
2015-11-03 21:06:22 -05:00
agc_mode_changed . store ( false ) ;
if ( ! agc_mode . load ( ) ) {
updateGains ( ) ;
2016-05-11 22:37:25 -04:00
DeviceConfig * devConfig = deviceConfig . load ( ) ;
ConfigGains gains = devConfig - > getGains ( ) ;
if ( gains . size ( ) ) {
for ( ConfigGains : : iterator gain_i = gains . begin ( ) ; gain_i ! = gains . end ( ) ; gain_i + + ) {
setGain ( gain_i - > first , gain_i - > second ) ;
}
}
2015-11-03 21:06:22 -05:00
}
2016-02-02 19:27:08 -05:00
doUpdate = true ;
2015-11-03 21:06:22 -05:00
}
if ( gain_value_changed . load ( ) & & ! agc_mode . load ( ) ) {
2016-06-02 23:56:31 +02:00
std : : lock_guard < std : : mutex > lock ( gain_busy ) ;
2015-11-03 21:06:22 -05:00
for ( std : : map < std : : string , bool > : : iterator gci = gainChanged . begin ( ) ; gci ! = gainChanged . end ( ) ; gci + + ) {
if ( gci - > second ) {
2016-01-31 15:11:54 -05:00
device - > setGain ( SOAPY_SDR_RX , 0 , gci - > first , gainValues [ gci - > first ] ) ;
2015-11-03 21:06:22 -05:00
gainChanged [ gci - > first ] = false ;
}
}
gain_value_changed . store ( false ) ;
}
if ( setting_value_changed . load ( ) ) {
2016-06-02 23:56:31 +02:00
std : : lock_guard < std : : mutex > lock ( setting_busy ) ;
2015-11-03 21:06:22 -05:00
for ( std : : map < std : : string , bool > : : iterator sci = settingChanged . begin ( ) ; sci ! = settingChanged . end ( ) ; sci + + ) {
if ( sci - > second ) {
device - > writeSetting ( sci - > first , settings [ sci - > first ] ) ;
settingChanged [ sci - > first ] = false ;
}
}
setting_value_changed . store ( false ) ;
2016-02-02 19:27:08 -05:00
doUpdate = true ;
}
if ( doUpdate ) {
wxGetApp ( ) . sdrThreadNotify ( SDRThread : : SDR_THREAD_INITIALIZED , std : : string ( " Settings updated. " ) ) ;
2015-11-03 21:06:22 -05:00
}
}
2015-10-03 21:35:11 -04:00
void SDRThread : : run ( ) {
//#ifdef __APPLE__
// pthread_t tID = pthread_self(); // ID of this thread
2015-10-14 00:54:48 -04:00
// int priority = sched_get_priority_max( SCHED_FIFO);
2015-10-03 21:35:11 -04:00
// sched_param prio = { priority }; // scheduling priority of thread
// pthread_setschedparam(tID, SCHED_FIFO, &prio);
//#endif
std : : cout < < " SDR thread starting. " < < std : : endl ;
2016-02-02 20:05:32 -05:00
SDRDeviceInfo * activeDev = deviceInfo . load ( ) ;
if ( activeDev ! = NULL ) {
2015-10-03 21:35:11 -04:00
std : : cout < < " device init() " < < std : : endl ;
2016-07-24 11:59:59 -04:00
if ( ! init ( ) ) {
std : : cout < < " SDR Thread stream init error. " < < std : : endl ;
return ;
}
2015-10-03 21:35:11 -04:00
std : : cout < < " starting readLoop() " < < std : : endl ;
2016-02-02 20:05:32 -05:00
activeDev - > setActive ( true ) ;
2015-10-03 21:35:11 -04:00
readLoop ( ) ;
2016-02-02 20:05:32 -05:00
activeDev - > setActive ( false ) ;
2015-10-03 21:35:11 -04:00
std : : cout < < " readLoop() ended. " < < std : : endl ;
deinit ( ) ;
std : : cout < < " device deinit() " < < std : : endl ;
} else {
2015-10-04 16:07:14 -04:00
std : : cout < < " SDR Thread started with null device? " < < std : : endl ;
2015-10-03 21:35:11 -04:00
}
2015-09-13 22:18:29 -04:00
std : : cout < < " SDR thread done. " < < std : : endl ;
}
2015-10-03 21:35:11 -04:00
SDRDeviceInfo * SDRThread : : getDevice ( ) {
return deviceInfo . load ( ) ;
2015-09-13 22:18:29 -04:00
}
2015-10-03 21:35:11 -04:00
void SDRThread : : setDevice ( SDRDeviceInfo * dev ) {
deviceInfo . store ( dev ) ;
2016-01-17 21:54:22 -05:00
if ( dev ) {
deviceConfig . store ( wxGetApp ( ) . getConfig ( ) - > getDevice ( dev - > getDeviceId ( ) ) ) ;
} else {
deviceConfig . store ( nullptr ) ;
}
2015-09-13 22:18:29 -04:00
}
2015-09-22 21:03:23 -04:00
int SDRThread : : getOptimalElementCount ( long long sampleRate , int fps ) {
int elemCount = ( int ) floor ( ( double ) sampleRate / ( double ) fps ) ;
2015-10-14 00:54:48 -04:00
int nch = numChannels . load ( ) ;
elemCount = int ( ceil ( ( double ) elemCount / ( double ) nch ) ) * nch ;
2016-05-11 22:37:25 -04:00
// std::cout << "Calculated optimal " << numChannels.load() << " channel element count of " << elemCount << std::endl;
2015-09-22 21:03:23 -04:00
return elemCount ;
}
2015-10-03 21:35:11 -04:00
2015-10-14 00:54:48 -04:00
int SDRThread : : getOptimalChannelCount ( long long sampleRate ) {
2015-12-29 20:52:49 -05:00
if ( sampleRate < = CHANNELIZER_RATE_MAX ) {
return 1 ;
}
2015-10-14 00:54:48 -04:00
int optimal_rate = CHANNELIZER_RATE_MAX ;
int optimal_count = int ( ceil ( double ( sampleRate ) / double ( optimal_rate ) ) ) ;
if ( optimal_count % 2 = = 1 ) {
optimal_count - - ;
}
2015-12-05 19:07:26 -05:00
if ( optimal_count < 2 ) {
optimal_count = 2 ;
2015-10-14 00:54:48 -04:00
}
2015-12-05 19:07:26 -05:00
2015-10-14 00:54:48 -04:00
return optimal_count ;
}
2015-10-03 21:35:11 -04:00
void SDRThread : : setFrequency ( long long freq ) {
if ( freq < sampleRate . load ( ) / 2 ) {
freq = sampleRate . load ( ) / 2 ;
}
frequency . store ( freq ) ;
freq_changed . store ( true ) ;
}
long long SDRThread : : getFrequency ( ) {
return frequency . load ( ) ;
}
2016-01-07 00:35:02 -05:00
void SDRThread : : lockFrequency ( long long freq ) {
lock_freq . store ( freq ) ;
frequency_locked . store ( true ) ;
frequency_lock_init . store ( false ) ;
setFrequency ( freq ) ;
}
bool SDRThread : : isFrequencyLocked ( ) {
return frequency_locked . load ( ) ;
}
void SDRThread : : unlockFrequency ( ) {
frequency_locked . store ( false ) ;
frequency_lock_init . store ( false ) ;
freq_changed . store ( true ) ;
}
2015-10-03 21:35:11 -04:00
void SDRThread : : setOffset ( long long ofs ) {
offset . store ( ofs ) ;
offset_changed . store ( true ) ;
2016-05-11 22:37:25 -04:00
// std::cout << "Set offset: " << offset.load() << std::endl;
2015-10-03 21:35:11 -04:00
}
long long SDRThread : : getOffset ( ) {
return offset . load ( ) ;
}
2017-01-21 11:26:51 +01:00
void SDRThread : : setSampleRate ( long rate ) {
2015-10-03 21:35:11 -04:00
sampleRate . store ( rate ) ;
rate_changed = true ;
2016-05-11 22:37:25 -04:00
DeviceConfig * devConfig = deviceConfig . load ( ) ;
if ( devConfig ) {
devConfig - > setSampleRate ( rate ) ;
}
// std::cout << "Set sample rate: " << sampleRate.load() << std::endl;
2015-10-03 21:35:11 -04:00
}
2017-01-21 11:26:51 +01:00
long SDRThread : : getSampleRate ( ) {
2015-10-03 21:35:11 -04:00
return sampleRate . load ( ) ;
}
void SDRThread : : setPPM ( int ppm ) {
this - > ppm . store ( ppm ) ;
ppm_changed . store ( true ) ;
2016-05-11 22:37:25 -04:00
// std::cout << "Set PPM: " << this->ppm.load() << std::endl;
2015-10-03 21:35:11 -04:00
}
int SDRThread : : getPPM ( ) {
return ppm . load ( ) ;
}
2015-10-27 01:56:49 -04:00
void SDRThread : : setAGCMode ( bool mode ) {
agc_mode . store ( mode ) ;
agc_mode_changed . store ( true ) ;
2016-05-11 22:37:25 -04:00
DeviceConfig * devConfig = deviceConfig . load ( ) ;
if ( devConfig ) {
devConfig - > setAGCMode ( mode ) ;
}
2015-10-27 01:56:49 -04:00
}
bool SDRThread : : getAGCMode ( ) {
return agc_mode . load ( ) ;
}
2016-02-15 15:07:57 -05:00
void SDRThread : : setIQSwap ( bool swap ) {
iq_swap . store ( swap ) ;
}
bool SDRThread : : getIQSwap ( ) {
return iq_swap . load ( ) ;
}
2015-10-27 01:56:49 -04:00
void SDRThread : : setGain ( std : : string name , float value ) {
2016-06-02 23:56:31 +02:00
std : : lock_guard < std : : mutex > lock ( gain_busy ) ;
2015-10-31 13:35:13 -04:00
gainValues [ name ] = value ;
gainChanged [ name ] = true ;
2015-10-27 01:56:49 -04:00
gain_value_changed . store ( true ) ;
2016-05-11 22:37:25 -04:00
DeviceConfig * devConfig = deviceConfig . load ( ) ;
if ( devConfig ) {
devConfig - > setGain ( name , value ) ;
}
2015-10-27 01:56:49 -04:00
}
float SDRThread : : getGain ( std : : string name ) {
2016-06-02 23:56:31 +02:00
std : : lock_guard < std : : mutex > lock ( gain_busy ) ;
2015-10-31 13:35:13 -04:00
float val = gainValues [ name ] ;
2016-06-02 23:56:31 +02:00
2015-10-31 13:35:13 -04:00
return val ;
2015-10-27 01:56:49 -04:00
}
2015-11-03 21:06:22 -05:00
void SDRThread : : writeSetting ( std : : string name , std : : string value ) {
2016-06-02 23:56:31 +02:00
std : : lock_guard < std : : mutex > lock ( setting_busy ) ;
2015-11-03 21:06:22 -05:00
settings [ name ] = value ;
settingChanged [ name ] = true ;
setting_value_changed . store ( true ) ;
2015-12-06 00:32:32 -05:00
if ( deviceConfig . load ( ) ! = nullptr ) {
deviceConfig . load ( ) - > setSetting ( name , value ) ;
}
2015-11-03 21:06:22 -05:00
}
std : : string SDRThread : : readSetting ( std : : string name ) {
std : : string val ;
2016-06-02 23:56:31 +02:00
std : : lock_guard < std : : mutex > lock ( setting_busy ) ;
2015-11-03 21:06:22 -05:00
val = device - > readSetting ( name ) ;
2016-06-02 23:56:31 +02:00
2015-11-03 21:06:22 -05:00
return val ;
}
2015-11-04 02:04:52 -05:00
void SDRThread : : setStreamArgs ( SoapySDR : : Kwargs streamArgs_in ) {
streamArgs = streamArgs_in ;
}