2017-09-04 07:32:31 -04:00
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
2017-09-04 16:23:39 -04:00
# include <QDebug>
2017-09-04 07:32:31 -04:00
# include "dsp/filerecord.h"
2017-09-07 16:24:09 -04:00
# include "dsp/dspcommands.h"
2017-09-04 16:23:39 -04:00
# include "device/devicesourceapi.h"
# include "device/devicesinkapi.h"
2017-09-05 18:23:47 -04:00
# include "plutosdr/deviceplutosdrparams.h"
# include "plutosdr/deviceplutosdrbox.h"
2017-09-04 07:32:31 -04:00
# include "plutosdrinput.h"
2017-09-06 12:48:58 -04:00
# include "plutosdrinputthread.h"
2017-09-04 07:32:31 -04:00
2017-09-10 10:58:48 -04:00
# define PLUTOSDR_BLOCKSIZE_SAMPLES (128*1024) //complex samples per buffer (must be multiple of 64)
2017-09-06 00:15:38 -04:00
2017-09-08 21:09:17 -04:00
MESSAGE_CLASS_DEFINITION ( PlutoSDRInput : : MsgConfigurePlutoSDR , Message )
2017-09-04 07:32:31 -04:00
MESSAGE_CLASS_DEFINITION ( PlutoSDRInput : : MsgFileRecord , Message )
PlutoSDRInput : : PlutoSDRInput ( DeviceSourceAPI * deviceAPI ) :
m_deviceAPI ( deviceAPI ) ,
m_fileSink ( 0 ) ,
m_deviceDescription ( " PlutoSDR " ) ,
2017-09-05 18:57:27 -04:00
m_running ( false ) ,
2017-09-06 12:48:58 -04:00
m_plutoRxBuffer ( 0 ) ,
m_plutoSDRInputThread ( 0 )
2017-09-04 07:32:31 -04:00
{
2017-09-08 21:09:17 -04:00
suspendBuddies ( ) ;
openDevice ( ) ;
resumeBuddies ( ) ;
2017-09-04 07:32:31 -04:00
char recFileNameCStr [ 30 ] ;
sprintf ( recFileNameCStr , " test_%d.sdriq " , m_deviceAPI - > getDeviceUID ( ) ) ;
m_fileSink = new FileRecord ( std : : string ( recFileNameCStr ) ) ;
m_deviceAPI - > addSink ( m_fileSink ) ;
}
PlutoSDRInput : : ~ PlutoSDRInput ( )
{
m_deviceAPI - > removeSink ( m_fileSink ) ;
delete m_fileSink ;
2017-09-08 21:09:17 -04:00
suspendBuddies ( ) ;
closeDevice ( ) ;
resumeBuddies ( ) ;
2017-09-04 07:32:31 -04:00
}
bool PlutoSDRInput : : start ( )
{
2017-09-05 19:01:17 -04:00
if ( ! m_deviceShared . m_deviceParams - > getBox ( ) ) {
return false ;
}
if ( m_running ) stop ( ) ;
applySettings ( m_settings , true ) ;
// start / stop streaming is done in the thread.
2017-09-10 10:58:48 -04:00
if ( ( m_plutoSDRInputThread = new PlutoSDRInputThread ( PLUTOSDR_BLOCKSIZE_SAMPLES , m_deviceShared . m_deviceParams - > getBox ( ) , & m_sampleFifo ) ) = = 0 )
2017-09-06 12:48:58 -04:00
{
qFatal ( " PlutoSDRInput::start: cannot create thread " ) ;
stop ( ) ;
return false ;
}
else
{
qDebug ( " PlutoSDRInput::start: thread created " ) ;
}
m_plutoSDRInputThread - > setLog2Decimation ( m_settings . m_log2Decim ) ;
m_plutoSDRInputThread - > startWork ( ) ;
m_deviceShared . m_thread = m_plutoSDRInputThread ;
m_running = true ;
2017-09-05 19:01:17 -04:00
return true ;
2017-09-04 07:32:31 -04:00
}
void PlutoSDRInput : : stop ( )
{
2017-09-06 12:48:58 -04:00
if ( m_plutoSDRInputThread ! = 0 )
{
m_plutoSDRInputThread - > stopWork ( ) ;
delete m_plutoSDRInputThread ;
m_plutoSDRInputThread = 0 ;
}
m_deviceShared . m_thread = 0 ;
m_running = false ;
2017-09-04 07:32:31 -04:00
}
const QString & PlutoSDRInput : : getDeviceDescription ( ) const
{
return m_deviceDescription ;
}
int PlutoSDRInput : : getSampleRate ( ) const
{
return ( m_settings . m_devSampleRate / ( 1 < < m_settings . m_log2Decim ) ) ;
}
quint64 PlutoSDRInput : : getCenterFrequency ( ) const
{
return m_settings . m_centerFrequency ;
}
bool PlutoSDRInput : : handleMessage ( const Message & message )
{
2017-09-06 12:48:58 -04:00
if ( MsgConfigurePlutoSDR : : match ( message ) )
{
MsgConfigurePlutoSDR & conf = ( MsgConfigurePlutoSDR & ) message ;
qDebug ( ) < < " PlutoSDRInput::handleMessage: MsgConfigurePlutoSDR " ;
if ( ! applySettings ( conf . getSettings ( ) , conf . getForce ( ) ) )
{
qDebug ( " PlutoSDRInput::handleMessage config error " ) ;
}
return true ;
}
else if ( MsgFileRecord : : match ( message ) )
2017-09-04 07:32:31 -04:00
{
MsgFileRecord & conf = ( MsgFileRecord & ) message ;
qDebug ( ) < < " PlutoSDRInput::handleMessage: MsgFileRecord: " < < conf . getStartStop ( ) ;
if ( conf . getStartStop ( ) ) {
m_fileSink - > startRecording ( ) ;
} else {
m_fileSink - > stopRecording ( ) ;
}
2017-09-04 16:23:39 -04:00
return true ;
2017-09-04 07:32:31 -04:00
}
else
{
return false ;
}
}
2017-09-05 10:23:10 -04:00
bool PlutoSDRInput : : openDevice ( )
{
2017-09-10 10:58:48 -04:00
if ( ! m_sampleFifo . setSize ( PLUTOSDR_BLOCKSIZE_SAMPLES ) )
2017-09-05 18:23:47 -04:00
{
qCritical ( " PlutoSDRInput::openDevice: could not allocate SampleFifo " ) ;
return false ;
}
else
{
qDebug ( " PlutoSDRInput::openDevice: allocated SampleFifo " ) ;
}
// look for Tx buddy and get reference to common parameters
if ( m_deviceAPI - > getSinkBuddies ( ) . size ( ) > 0 ) // then sink
{
qDebug ( " PlutoSDRInput::openDevice: look at Tx buddy " ) ;
DeviceSinkAPI * sinkBuddy = m_deviceAPI - > getSinkBuddies ( ) [ 0 ] ;
m_deviceShared = * ( ( DevicePlutoSDRShared * ) sinkBuddy - > getBuddySharedPtr ( ) ) ; // copy parameters
if ( m_deviceShared . m_deviceParams = = 0 )
{
qCritical ( " PlutoSDRInput::openDevice: cannot get device parameters from Tx buddy " ) ;
return false ; // the device params should have been created by the buddy
}
else
{
qDebug ( " PlutoSDRInput::openDevice: getting device parameters from Tx buddy " ) ;
}
}
// There is no buddy then create the first PlutoSDR common parameters
// open the device this will also populate common fields
else
{
qDebug ( " PlutoSDRInput::openDevice: open device here " ) ;
m_deviceShared . m_deviceParams = new DevicePlutoSDRParams ( ) ;
char serial [ 256 ] ;
strcpy ( serial , qPrintable ( m_deviceAPI - > getSampleSourceSerial ( ) ) ) ;
m_deviceShared . m_deviceParams - > open ( serial ) ;
}
m_deviceAPI - > setBuddySharedPtr ( & m_deviceShared ) ; // propagate common parameters to API
// acquire the channel
DevicePlutoSDRBox * plutoBox = m_deviceShared . m_deviceParams - > getBox ( ) ;
plutoBox - > openRx ( ) ;
2017-09-10 10:58:48 -04:00
m_plutoRxBuffer = plutoBox - > createRxBuffer ( PLUTOSDR_BLOCKSIZE_SAMPLES * 2 , false ) ; // PlutoSDR buffer size is counted in number of I or Q samples not the combination
2017-09-05 19:01:17 -04:00
return true ;
2017-09-05 10:23:10 -04:00
}
void PlutoSDRInput : : closeDevice ( )
{
2017-09-05 18:57:27 -04:00
if ( m_deviceShared . m_deviceParams - > getBox ( ) = = 0 ) { // was never open
return ;
}
2017-09-05 10:23:10 -04:00
2017-09-05 18:57:27 -04:00
if ( m_deviceAPI - > getSinkBuddies ( ) . size ( ) = = 0 )
{
m_deviceShared . m_deviceParams - > close ( ) ;
delete m_deviceShared . m_deviceParams ;
m_deviceShared . m_deviceParams = 0 ;
}
2017-09-05 10:23:10 -04:00
}
void PlutoSDRInput : : suspendBuddies ( )
{
2017-09-05 18:57:27 -04:00
// suspend Tx buddy's thread
2017-09-05 10:23:10 -04:00
2017-09-05 18:57:27 -04:00
for ( unsigned int i = 0 ; i < m_deviceAPI - > getSinkBuddies ( ) . size ( ) ; i + + )
{
DeviceSinkAPI * buddy = m_deviceAPI - > getSinkBuddies ( ) [ i ] ;
DevicePlutoSDRShared * buddyShared = ( DevicePlutoSDRShared * ) buddy - > getBuddySharedPtr ( ) ;
if ( buddyShared - > m_thread ) {
buddyShared - > m_thread - > stopWork ( ) ;
}
}
2017-09-05 10:23:10 -04:00
}
void PlutoSDRInput : : resumeBuddies ( )
{
2017-09-05 18:57:27 -04:00
// resume Tx buddy's thread
for ( unsigned int i = 0 ; i < m_deviceAPI - > getSinkBuddies ( ) . size ( ) ; i + + )
{
DeviceSinkAPI * buddy = m_deviceAPI - > getSinkBuddies ( ) [ i ] ;
DevicePlutoSDRShared * buddyShared = ( DevicePlutoSDRShared * ) buddy - > getBuddySharedPtr ( ) ;
if ( buddyShared - > m_thread ) {
buddyShared - > m_thread - > startWork ( ) ;
}
}
2017-09-05 19:01:17 -04:00
}
2017-09-05 10:23:10 -04:00
2017-09-05 19:01:17 -04:00
bool PlutoSDRInput : : applySettings ( const PlutoSDRInputSettings & settings , bool force )
{
2017-09-06 12:48:58 -04:00
bool forwardChangeOwnDSP = false ;
2017-09-07 12:41:55 -04:00
bool forwardChangeOtherDSP = false ;
2017-09-06 12:48:58 -04:00
bool suspendOwnThread = false ;
bool ownThreadWasRunning = false ;
bool suspendAllOtherThreads = false ; // All others means Tx in fact
2017-09-07 12:41:55 -04:00
DevicePlutoSDRBox * plutoBox = m_deviceShared . m_deviceParams - > getBox ( ) ;
2017-09-06 12:48:58 -04:00
// determine if buddies threads or own thread need to be suspended
2017-09-08 21:09:17 -04:00
// changes affecting all buddies can occur if
2017-09-06 12:48:58 -04:00
// - device to host sample rate is changed
2017-09-07 00:15:39 -04:00
// - FIR filter is enabled or disabled
2017-09-08 21:09:17 -04:00
// - FIR filter is changed
// - LO correction is changed
2017-09-06 12:48:58 -04:00
if ( ( m_settings . m_devSampleRate ! = settings . m_devSampleRate ) | |
2017-09-08 21:09:17 -04:00
( m_settings . m_lpfFIREnable ! = settings . m_lpfFIREnable ) | |
2017-09-07 00:15:39 -04:00
( m_settings . m_lpfFIRlog2Decim ! = settings . m_lpfFIRlog2Decim ) | |
2017-09-08 21:09:17 -04:00
( settings . m_lpfFIRBW ! = m_settings . m_lpfFIRBW ) | |
( settings . m_lpfFIRGain ! = m_settings . m_lpfFIRGain ) | |
( m_settings . m_LOppmTenths ! = settings . m_LOppmTenths ) | | force )
2017-09-06 12:48:58 -04:00
{
suspendAllOtherThreads = true ;
suspendOwnThread = true ;
}
else
{
suspendOwnThread = true ;
}
if ( suspendAllOtherThreads )
{
const std : : vector < DeviceSinkAPI * > & sinkBuddies = m_deviceAPI - > getSinkBuddies ( ) ;
std : : vector < DeviceSinkAPI * > : : const_iterator itSink = sinkBuddies . begin ( ) ;
for ( ; itSink ! = sinkBuddies . end ( ) ; + + itSink )
{
DevicePlutoSDRShared * buddySharedPtr = ( DevicePlutoSDRShared * ) ( * itSink ) - > getBuddySharedPtr ( ) ;
if ( buddySharedPtr - > m_thread ) {
buddySharedPtr - > m_thread - > stopWork ( ) ;
buddySharedPtr - > m_threadWasRunning = true ;
}
else
{
buddySharedPtr - > m_threadWasRunning = false ;
}
}
}
if ( suspendOwnThread )
{
if ( m_plutoSDRInputThread & & m_plutoSDRInputThread - > isRunning ( ) )
{
m_plutoSDRInputThread - > stopWork ( ) ;
ownThreadWasRunning = true ;
}
}
2017-09-10 12:35:38 -04:00
// apply settings
2017-09-06 12:48:58 -04:00
2017-09-07 17:27:24 -04:00
if ( ( m_settings . m_dcBlock ! = settings . m_dcBlock ) | |
( m_settings . m_iqCorrection ! = settings . m_iqCorrection ) | | force )
{
m_deviceAPI - > configureCorrections ( settings . m_dcBlock , m_settings . m_iqCorrection ) ;
}
2017-09-08 21:09:17 -04:00
// Change affecting device sample rate chain and other buddies
2017-09-06 12:48:58 -04:00
if ( ( m_settings . m_devSampleRate ! = settings . m_devSampleRate ) | |
2017-09-08 21:09:17 -04:00
( m_settings . m_lpfFIREnable ! = settings . m_lpfFIREnable ) | |
2017-09-07 00:15:39 -04:00
( m_settings . m_lpfFIRlog2Decim ! = settings . m_lpfFIRlog2Decim ) | |
2017-09-08 21:09:17 -04:00
( settings . m_lpfFIRBW ! = m_settings . m_lpfFIRBW ) | |
( settings . m_lpfFIRGain ! = m_settings . m_lpfFIRGain ) | | force )
2017-09-06 12:48:58 -04:00
{
2017-09-10 12:35:38 -04:00
plutoBox - > setFIR ( settings . m_devSampleRate , settings . m_lpfFIRlog2Decim , settings . m_lpfFIRBW , settings . m_lpfFIRGain ) ; // don't bother with the FIR at this point
plutoBox - > setFIREnable ( settings . m_lpfFIREnable ) ; // eventually enable/disable FIR
plutoBox - > setSampleRate ( settings . m_devSampleRate ) ; // and set end point sample rate
2017-09-07 12:41:55 -04:00
plutoBox - > getRxSampleRates ( m_deviceSampleRates ) ; // pick up possible new rates
2017-09-09 09:34:04 -04:00
qDebug ( ) < < " PlutoSDRInput::applySettings: BBPLL(Hz): " < < m_deviceSampleRates . m_bbRateHz
2017-09-10 04:16:23 -04:00
< < " ADC: " < < m_deviceSampleRates . m_addaConnvRate
< < " -HB3-> " < < m_deviceSampleRates . m_hb3Rate
< < " -HB2-> " < < m_deviceSampleRates . m_hb2Rate
< < " -HB1-> " < < m_deviceSampleRates . m_hb1Rate
< < " -FIR-> " < < m_deviceSampleRates . m_firRate ;
2017-09-07 12:41:55 -04:00
forwardChangeOtherDSP = true ;
forwardChangeOwnDSP = ( m_settings . m_devSampleRate ! = settings . m_devSampleRate ) ;
}
if ( ( m_settings . m_log2Decim ! = settings . m_log2Decim ) | | force )
{
if ( m_plutoSDRInputThread ! = 0 )
{
m_plutoSDRInputThread - > setLog2Decimation ( settings . m_log2Decim ) ;
2017-09-07 17:27:24 -04:00
qDebug ( ) < < " PlutoSDRInput::applySettings: set soft decimation to " < < ( 1 < < settings . m_log2Decim ) ;
2017-09-07 12:41:55 -04:00
}
forwardChangeOwnDSP = true ;
}
2017-09-07 17:27:24 -04:00
if ( ( m_settings . m_fcPos ! = settings . m_fcPos ) | | force )
{
if ( m_plutoSDRInputThread ! = 0 )
{
m_plutoSDRInputThread - > setFcPos ( settings . m_fcPos ) ;
qDebug ( ) < < " PlutoSDRInput::applySettings: set fcPos to " < < ( 1 < < settings . m_fcPos ) ;
}
}
2017-09-10 11:18:08 -04:00
if ( ( m_settings . m_LOppmTenths ! = settings . m_LOppmTenths ) | | force )
{
plutoBox - > setLOPPMTenths ( settings . m_LOppmTenths ) ;
}
2017-09-10 05:30:52 -04:00
2017-09-08 02:41:57 -04:00
std : : vector < std : : string > params ;
bool paramsToSet = false ;
2017-09-07 12:41:55 -04:00
if ( ( m_settings . m_centerFrequency ! = settings . m_centerFrequency ) | | force )
{
2017-09-07 17:27:24 -04:00
params . push_back ( QString ( tr ( " out_altvoltage0_RX_LO_frequency=%1 " ) . arg ( settings . m_centerFrequency ) ) . toStdString ( ) ) ;
2017-09-08 02:41:57 -04:00
paramsToSet = true ;
2017-09-07 12:41:55 -04:00
forwardChangeOwnDSP = true ;
2017-09-06 12:48:58 -04:00
}
2017-09-07 17:27:24 -04:00
if ( ( m_settings . m_lpfBW ! = settings . m_lpfBW ) | | force )
{
params . push_back ( QString ( tr ( " in_voltage_rf_bandwidth=%1 " ) . arg ( settings . m_lpfBW ) ) . toStdString ( ) ) ;
2017-09-08 02:41:57 -04:00
paramsToSet = true ;
2017-09-07 17:27:24 -04:00
}
if ( ( m_settings . m_antennaPath ! = settings . m_antennaPath ) | | force )
{
QString rfPortStr ;
PlutoSDRInputSettings : : translateRFPath ( settings . m_antennaPath , rfPortStr ) ;
params . push_back ( QString ( tr ( " in_voltage0_rf_port_select=%1 " ) . arg ( rfPortStr ) ) . toStdString ( ) ) ;
2017-09-08 02:41:57 -04:00
paramsToSet = true ;
2017-09-07 17:27:24 -04:00
}
if ( ( m_settings . m_gainMode ! = settings . m_gainMode ) | | force )
{
QString gainModeStr ;
PlutoSDRInputSettings : : translateGainMode ( settings . m_gainMode , gainModeStr ) ;
params . push_back ( QString ( tr ( " in_voltage0_gain_control_mode=%1 " ) . arg ( gainModeStr ) ) . toStdString ( ) ) ;
2017-09-08 02:41:57 -04:00
paramsToSet = true ;
2017-09-07 17:27:24 -04:00
}
2017-09-07 12:41:55 -04:00
2017-09-07 17:27:24 -04:00
if ( ( m_settings . m_gain ! = settings . m_gain ) | | force )
2017-09-07 16:24:09 -04:00
{
2017-09-07 17:27:24 -04:00
params . push_back ( QString ( tr ( " in_voltage0_hardwaregain=%1 " ) . arg ( settings . m_gain ) ) . toStdString ( ) ) ;
2017-09-08 02:41:57 -04:00
paramsToSet = true ;
}
if ( paramsToSet )
{
2017-09-07 17:27:24 -04:00
plutoBox - > set_params ( DevicePlutoSDRBox : : DEVICE_PHY , params ) ;
2017-09-07 16:24:09 -04:00
}
2017-09-07 17:27:24 -04:00
m_settings = settings ;
2017-09-06 12:48:58 -04:00
if ( suspendAllOtherThreads )
{
const std : : vector < DeviceSinkAPI * > & sinkBuddies = m_deviceAPI - > getSinkBuddies ( ) ;
std : : vector < DeviceSinkAPI * > : : const_iterator itSink = sinkBuddies . begin ( ) ;
for ( ; itSink ! = sinkBuddies . end ( ) ; + + itSink )
{
DevicePlutoSDRShared * buddySharedPtr = ( DevicePlutoSDRShared * ) ( * itSink ) - > getBuddySharedPtr ( ) ;
if ( buddySharedPtr - > m_threadWasRunning ) {
buddySharedPtr - > m_thread - > startWork ( ) ;
}
}
}
if ( suspendOwnThread )
{
if ( ownThreadWasRunning ) {
m_plutoSDRInputThread - > startWork ( ) ;
}
}
2017-09-07 12:41:55 -04:00
// TODO: forward changes to other (Tx) DSP
2017-09-07 16:24:09 -04:00
if ( forwardChangeOtherDSP )
{
qDebug ( " PlutoSDRInput::applySettings: forwardChangeOtherDSP " ) ;
}
2017-09-07 12:41:55 -04:00
if ( forwardChangeOwnDSP )
{
qDebug ( " PlutoSDRInput::applySettings: forward change to self " ) ;
int sampleRate = m_settings . m_devSampleRate / ( 1 < < m_settings . m_log2Decim ) ;
DSPSignalNotification * notif = new DSPSignalNotification ( sampleRate , m_settings . m_centerFrequency ) ;
m_fileSink - > handleMessage ( * notif ) ; // forward to file sink
m_deviceAPI - > getDeviceInputMessageQueue ( ) - > push ( notif ) ;
}
2017-09-08 21:09:17 -04:00
return true ;
}
void PlutoSDRInput : : getRSSI ( std : : string & rssiStr )
{
DevicePlutoSDRBox * plutoBox = m_deviceShared . m_deviceParams - > getBox ( ) ;
if ( ! plutoBox - > getRSSI ( rssiStr , 0 ) ) {
rssiStr = " xxx dB " ;
}
}
bool PlutoSDRInput : : fetchTemperature ( )
{
DevicePlutoSDRBox * plutoBox = m_deviceShared . m_deviceParams - > getBox ( ) ;
return plutoBox - > fetchTemp ( ) ;
}
float PlutoSDRInput : : getTemperature ( )
{
DevicePlutoSDRBox * plutoBox = m_deviceShared . m_deviceParams - > getBox ( ) ;
return plutoBox - > getTemp ( ) ;
2017-09-05 10:23:10 -04:00
}