2015-09-24 02:50:24 +02:00
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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-01-08 00:33:11 +01:00
#include "hackrfinput.h"
2016-12-27 03:14:50 +01:00
2015-09-24 02:50:24 +02:00
#include <string.h>
#include <errno.h>
#include <QDebug>
#include "util/simpleserializer.h"
#include "dsp/dspcommands.h"
2015-09-27 12:50:38 +02:00
#include "dsp/dspengine.h"
2017-01-08 00:33:11 +01:00
#include "device/devicesourceapi.h"
#include "device/devicesinkapi.h"
2017-01-08 02:48:01 +01:00
#include "hackrf/devicehackrfvalues.h"
2017-07-21 00:44:30 +02:00
#include "hackrf/devicehackrfshared.h"
2016-10-11 01:17:55 +02:00
2017-01-07 11:24:09 +01:00
#include "hackrfinputgui.h"
#include "hackrfinputthread.h"
2015-09-24 02:50:24 +02:00
2015-09-27 07:37:15 +02:00
MESSAGE_CLASS_DEFINITION ( HackRFInput :: MsgConfigureHackRF , Message )
2015-09-24 02:50:24 +02:00
MESSAGE_CLASS_DEFINITION ( HackRFInput :: MsgReportHackRF , Message )
2016-10-11 01:17:55 +02:00
HackRFInput :: HackRFInput ( DeviceSourceAPI * deviceAPI ) :
2016-05-16 02:14:36 +02:00
m_deviceAPI ( deviceAPI ),
2015-09-24 02:50:24 +02:00
m_settings (),
m_dev ( 0 ),
2015-09-27 07:37:15 +02:00
m_hackRFThread ( 0 ),
2017-04-14 00:14:40 +02:00
m_deviceDescription ( "HackRF" ),
m_running ( false )
2015-09-24 02:50:24 +02:00
{
2017-04-14 00:14:40 +02:00
openDevice ();
2017-01-08 00:33:11 +01:00
m_deviceAPI -> setBuddySharedPtr ( & m_sharedParams );
2015-09-24 02:50:24 +02:00
}
HackRFInput ::~ HackRFInput ()
{
2017-04-14 00:14:40 +02:00
if ( m_running ) stop ();
closeDevice ();
2017-01-08 00:33:11 +01:00
m_deviceAPI -> setBuddySharedPtr ( 0 );
2015-09-24 02:50:24 +02:00
}
2017-04-14 00:14:40 +02:00
bool HackRFInput :: openDevice ()
2015-09-24 02:50:24 +02:00
{
2017-01-08 00:33:11 +01:00
if ( m_dev != 0 )
{
2017-04-14 00:14:40 +02:00
closeDevice ();
2017-01-08 00:33:11 +01:00
}
2017-04-14 00:14:40 +02:00
if ( ! m_sampleFifo . setSize ( 1 << 19 ))
{
qCritical ( "HackRFInput::start: could not allocate SampleFifo" );
return false ;
}
2015-09-24 02:50:24 +02:00
2017-01-08 00:33:11 +01:00
if ( m_deviceAPI -> getSinkBuddies (). size () > 0 )
{
DeviceSinkAPI * buddy = m_deviceAPI -> getSinkBuddies ()[ 0 ];
DeviceHackRFParams * buddySharedParams = ( DeviceHackRFParams * ) buddy -> getBuddySharedPtr ();
if ( buddySharedParams == 0 )
{
2017-04-14 00:14:40 +02:00
qCritical ( "HackRFInput::openDevice: could not get shared parameters from buddy" );
2017-01-08 00:33:11 +01:00
return false ;
}
2017-04-14 01:41:02 +02:00
if ( buddySharedParams -> m_dev == 0 ) // device is not opened by buddy
2017-01-08 00:33:11 +01:00
{
2017-04-14 01:41:02 +02:00
qCritical ( "HackRFInput::openDevice: could not get HackRF handle from buddy" );
return false ;
2017-01-08 00:33:11 +01:00
}
2017-04-14 01:41:02 +02:00
m_sharedParams = * ( buddySharedParams ); // copy parameters from buddy
m_dev = m_sharedParams . m_dev ; // get HackRF handle
2017-01-08 00:33:11 +01:00
}
2017-04-14 01:41:02 +02:00
else
2017-01-08 00:33:11 +01:00
{
2017-04-14 02:09:36 +02:00
if (( m_dev = DeviceHackRF :: open_hackrf ( qPrintable ( m_deviceAPI -> getSampleSourceSerial ()))) == 0 )
2017-01-08 00:33:11 +01:00
{
2017-04-14 02:09:36 +02:00
qCritical ( "HackRFInput::openDevice: could not open HackRF %s" , qPrintable ( m_deviceAPI -> getSampleSourceSerial ()));
2017-01-08 00:33:11 +01:00
return false ;
}
m_sharedParams . m_dev = m_dev ;
}
2015-09-24 02:50:24 +02:00
2017-04-14 00:14:40 +02:00
return true ;
}
2017-04-14 03:40:45 +02:00
bool HackRFInput :: start ()
2017-04-14 00:14:40 +02:00
{
// QMutexLocker mutexLocker(&m_mutex);
2017-04-14 01:41:02 +02:00
if ( ! m_dev ) {
return false ;
2017-04-14 00:14:40 +02:00
}
if ( m_running ) stop ();
if (( m_hackRFThread = new HackRFInputThread ( m_dev , & m_sampleFifo )) == 0 )
2015-09-24 02:50:24 +02:00
{
2015-09-27 07:37:15 +02:00
qFatal ( "HackRFInput::start: out of memory" );
2015-09-24 02:50:24 +02:00
stop ();
return false ;
}
2017-01-08 00:33:11 +01:00
// mutexLocker.unlock();
2015-09-24 02:50:24 +02:00
applySettings ( m_settings , true );
2017-04-14 00:14:40 +02:00
m_hackRFThread -> setSamplerate ( m_settings . m_devSampleRate );
m_hackRFThread -> setLog2Decimation ( m_settings . m_log2Decim );
m_hackRFThread -> setFcPos (( int ) m_settings . m_fcPos );
2015-10-21 02:32:21 +02:00
m_hackRFThread -> startWork ();
2015-09-27 07:37:15 +02:00
qDebug ( "HackRFInput::startInput: started" );
2017-04-14 00:14:40 +02:00
m_running = true ;
2015-09-24 02:50:24 +02:00
return true ;
}
2017-04-14 00:14:40 +02:00
void HackRFInput :: closeDevice ()
2015-09-24 02:50:24 +02:00
{
2017-04-14 01:41:02 +02:00
if ( m_deviceAPI -> getSinkBuddies (). size () == 0 )
2017-01-08 00:33:11 +01:00
{
2017-04-14 01:41:02 +02:00
qDebug ( "HackRFInput::closeDevice: closing device since Tx side is not open" );
2017-01-08 00:33:11 +01:00
if ( m_dev != 0 ) // close BladeRF
{
hackrf_close ( m_dev );
2017-04-14 01:49:48 +02:00
//hackrf_exit(); // TODO: this may not work if several HackRF Devices are running concurrently. It should be handled globally in the application
2017-01-08 00:33:11 +01:00
}
}
m_sharedParams . m_dev = 0 ;
m_dev = 0 ;
2017-04-14 00:14:40 +02:00
}
void HackRFInput :: stop ()
{
qDebug ( "HackRFInput::stop" );
// QMutexLocker mutexLocker(&m_mutex);
if ( m_hackRFThread != 0 )
{
m_hackRFThread -> stopWork ();
delete m_hackRFThread ;
m_hackRFThread = 0 ;
}
2017-01-08 00:33:11 +01:00
2017-04-14 00:14:40 +02:00
m_running = false ;
2015-09-24 02:50:24 +02:00
}
const QString & HackRFInput :: getDeviceDescription () const
{
return m_deviceDescription ;
}
int HackRFInput :: getSampleRate () const
{
2017-01-08 02:48:01 +01:00
return ( m_settings . m_devSampleRate / ( 1 << m_settings . m_log2Decim ));
2015-09-24 02:50:24 +02:00
}
quint64 HackRFInput :: getCenterFrequency () const
{
return m_settings . m_centerFrequency ;
}
bool HackRFInput :: handleMessage ( const Message & message )
{
2015-09-27 07:37:15 +02:00
if ( MsgConfigureHackRF :: match ( message ))
2015-09-24 02:50:24 +02:00
{
2015-09-27 07:37:15 +02:00
MsgConfigureHackRF & conf = ( MsgConfigureHackRF & ) message ;
qDebug () << "HackRFInput::handleMessage: MsgConfigureHackRF" ;
2015-09-24 02:50:24 +02:00
2017-05-26 17:42:57 +02:00
bool success = applySettings ( conf . getSettings (), conf . getForce ());
2015-09-24 02:50:24 +02:00
if ( ! success )
{
2015-09-27 07:37:15 +02:00
qDebug ( "HackRFInput::handleMessage: config error" );
2015-09-24 02:50:24 +02:00
}
return true ;
}
else
{
return false ;
}
}
void HackRFInput :: setCenterFrequency ( quint64 freq_hz )
{
2015-09-27 18:32:19 +02:00
qint64 df = (( qint64 ) freq_hz * m_settings . m_LOppmTenths ) / 10000000LL ;
freq_hz += df ;
2015-09-24 02:50:24 +02:00
2015-09-27 07:37:15 +02:00
hackrf_error rc = ( hackrf_error ) hackrf_set_freq ( m_dev , static_cast < uint64_t > ( freq_hz ));
2015-09-24 02:50:24 +02:00
2015-09-27 07:37:15 +02:00
if ( rc != HACKRF_SUCCESS )
2015-09-24 02:50:24 +02:00
{
2015-09-27 07:37:15 +02:00
qWarning ( "HackRFInput::setCenterFrequency: could not frequency to %llu Hz" , freq_hz );
2015-09-24 02:50:24 +02:00
}
else
{
2015-09-27 07:37:15 +02:00
qWarning ( "HackRFInput::setCenterFrequency: frequency set to %llu Hz" , freq_hz );
2015-09-24 02:50:24 +02:00
}
}
2016-12-27 02:25:06 +01:00
bool HackRFInput :: applySettings ( const HackRFInputSettings & settings , bool force )
2015-09-24 02:50:24 +02:00
{
2017-01-08 00:33:11 +01:00
// QMutexLocker mutexLocker(&m_mutex);
2015-09-24 02:50:24 +02:00
bool forwardChange = false ;
2015-09-27 07:37:15 +02:00
hackrf_error rc ;
2015-09-24 02:50:24 +02:00
2015-09-27 07:37:15 +02:00
qDebug () << "HackRFInput::applySettings" ;
2015-09-24 02:50:24 +02:00
2015-09-30 04:39:09 +02:00
if ( m_settings . m_dcBlock != settings . m_dcBlock )
{
m_settings . m_dcBlock = settings . m_dcBlock ;
2016-05-16 02:14:36 +02:00
m_deviceAPI -> configureCorrections ( m_settings . m_dcBlock , m_settings . m_iqCorrection );
2015-09-30 04:39:09 +02:00
}
if ( m_settings . m_iqCorrection != settings . m_iqCorrection )
{
m_settings . m_iqCorrection = settings . m_iqCorrection ;
2016-05-16 02:14:36 +02:00
m_deviceAPI -> configureCorrections ( m_settings . m_dcBlock , m_settings . m_iqCorrection );
2015-09-30 04:39:09 +02:00
}
2017-01-08 02:48:01 +01:00
if (( m_settings . m_devSampleRate != settings . m_devSampleRate ) || force )
2015-09-24 02:50:24 +02:00
{
2017-01-08 04:13:20 +01:00
m_settings . m_devSampleRate = settings . m_devSampleRate ;
forwardChange = true ;
2015-09-24 02:50:24 +02:00
2017-01-08 04:13:20 +01:00
if ( m_dev != 0 )
2015-09-24 02:50:24 +02:00
{
2017-01-08 04:13:20 +01:00
rc = ( hackrf_error ) hackrf_set_sample_rate_manual ( m_dev , m_settings . m_devSampleRate , 1 );
2015-09-24 02:50:24 +02:00
2015-09-27 07:37:15 +02:00
if ( rc != HACKRF_SUCCESS )
2015-09-24 02:50:24 +02:00
{
2017-04-01 13:08:41 +02:00
qCritical ( "HackRFInput::applySettings: could not set sample rate TO %llu S/s: %s" , m_settings . m_devSampleRate , hackrf_error_name ( rc ));
2015-09-24 02:50:24 +02:00
}
else
{
2017-04-14 00:14:40 +02:00
if ( m_hackRFThread != 0 )
{
qDebug ( "HackRFInput::applySettings: sample rate set to %llu S/s" , m_settings . m_devSampleRate );
m_hackRFThread -> setSamplerate ( m_settings . m_devSampleRate );
}
2015-09-24 02:50:24 +02:00
}
}
}
if (( m_settings . m_log2Decim != settings . m_log2Decim ) || force )
{
m_settings . m_log2Decim = settings . m_log2Decim ;
forwardChange = true ;
2017-04-14 00:14:40 +02:00
if ( m_hackRFThread != 0 )
2015-09-24 02:50:24 +02:00
{
2015-09-27 07:37:15 +02:00
m_hackRFThread -> setLog2Decimation ( m_settings . m_log2Decim );
qDebug () << "HackRFInput: set decimation to " << ( 1 << m_settings . m_log2Decim );
2015-09-24 02:50:24 +02:00
}
}
qint64 deviceCenterFrequency = m_settings . m_centerFrequency ;
qint64 f_img = deviceCenterFrequency ;
2017-01-08 02:48:01 +01:00
quint32 devSampleRate = m_settings . m_devSampleRate ;
2015-09-24 02:50:24 +02:00
2017-07-21 00:44:30 +02:00
if ( force || ( m_settings . m_centerFrequency != settings . m_centerFrequency )) // forward delta to buddy if necessary
{
if ( m_settings . m_linkTxFrequency && ( m_deviceAPI -> getSinkBuddies (). size () > 0 ))
{
DeviceSinkAPI * buddy = m_deviceAPI -> getSinkBuddies ()[ 0 ];
DeviceHackRFShared :: MsgConfigureFrequencyDelta * deltaMsg = DeviceHackRFShared :: MsgConfigureFrequencyDelta :: create ( settings . m_centerFrequency - m_settings . m_centerFrequency );
buddy -> getDeviceOutputMessageQueue () -> push ( deltaMsg );
}
}
2015-09-24 02:50:24 +02:00
if ( force || ( m_settings . m_centerFrequency != settings . m_centerFrequency ) ||
2015-10-01 06:34:08 +02:00
( m_settings . m_LOppmTenths != settings . m_LOppmTenths ) ||
( m_settings . m_fcPos != settings . m_fcPos ))
2015-09-24 02:50:24 +02:00
{
m_settings . m_centerFrequency = settings . m_centerFrequency ;
m_settings . m_LOppmTenths = settings . m_LOppmTenths ;
2016-12-27 02:25:06 +01:00
if (( m_settings . m_log2Decim == 0 ) || ( settings . m_fcPos == HackRFInputSettings :: FC_POS_CENTER ))
2015-09-24 02:50:24 +02:00
{
deviceCenterFrequency = m_settings . m_centerFrequency ;
f_img = deviceCenterFrequency ;
}
else
{
2016-12-27 02:25:06 +01:00
if ( settings . m_fcPos == HackRFInputSettings :: FC_POS_INFRA )
2015-09-24 02:50:24 +02:00
{
deviceCenterFrequency = m_settings . m_centerFrequency + ( devSampleRate / 4 );
f_img = deviceCenterFrequency + devSampleRate / 2 ;
}
2016-12-27 02:25:06 +01:00
else if ( settings . m_fcPos == HackRFInputSettings :: FC_POS_SUPRA )
2015-09-24 02:50:24 +02:00
{
deviceCenterFrequency = m_settings . m_centerFrequency - ( devSampleRate / 4 );
f_img = deviceCenterFrequency - devSampleRate / 2 ;
}
}
if ( m_dev != 0 )
{
setCenterFrequency ( deviceCenterFrequency );
2015-09-27 07:37:15 +02:00
qDebug () << "HackRFInput::applySettings: center freq: " << m_settings . m_centerFrequency << " Hz"
2015-09-24 02:50:24 +02:00
<< " device center freq: " << deviceCenterFrequency << " Hz"
<< " device sample rate: " << devSampleRate << "Hz"
<< " Actual sample rate: " << devSampleRate / ( 1 << m_settings . m_log2Decim ) << "Hz"
<< " img: " << f_img << "Hz" ;
}
forwardChange = true ;
}
2015-10-01 06:34:08 +02:00
if (( m_settings . m_fcPos != settings . m_fcPos ) || force )
{
m_settings . m_fcPos = settings . m_fcPos ;
2017-04-14 00:14:40 +02:00
if ( m_hackRFThread != 0 )
2015-10-01 06:34:08 +02:00
{
m_hackRFThread -> setFcPos (( int ) m_settings . m_fcPos );
qDebug () << "HackRFInput: set fc pos (enum) to " << ( int ) m_settings . m_fcPos ;
}
}
2015-09-24 02:50:24 +02:00
if (( m_settings . m_lnaGain != settings . m_lnaGain ) || force )
{
m_settings . m_lnaGain = settings . m_lnaGain ;
if ( m_dev != 0 )
{
2015-09-27 07:37:15 +02:00
rc = ( hackrf_error ) hackrf_set_lna_gain ( m_dev , m_settings . m_lnaGain );
2015-09-24 02:50:24 +02:00
2015-09-27 07:37:15 +02:00
if ( rc != HACKRF_SUCCESS )
2015-09-24 02:50:24 +02:00
{
2015-09-27 07:37:15 +02:00
qDebug ( "HackRFInput::applySettings: airspy_set_lna_gain failed: %s" , hackrf_error_name ( rc ));
2015-09-24 02:50:24 +02:00
}
else
{
2015-09-27 07:37:15 +02:00
qDebug () << "HackRFInput:applySettings: LNA gain set to " << m_settings . m_lnaGain ;
2015-09-24 02:50:24 +02:00
}
}
}
2015-09-27 07:37:15 +02:00
if (( m_settings . m_vgaGain != settings . m_vgaGain ) || force )
2015-09-24 02:50:24 +02:00
{
2015-09-27 07:37:15 +02:00
m_settings . m_vgaGain = settings . m_vgaGain ;
2015-09-24 02:50:24 +02:00
if ( m_dev != 0 )
{
2015-09-27 07:37:15 +02:00
rc = ( hackrf_error ) hackrf_set_vga_gain ( m_dev , m_settings . m_vgaGain );
2015-09-24 02:50:24 +02:00
2015-09-27 07:37:15 +02:00
if ( rc != HACKRF_SUCCESS )
2015-09-24 02:50:24 +02:00
{
2015-09-27 07:37:15 +02:00
qDebug ( "HackRFInput::applySettings: hackrf_set_vga_gain failed: %s" , hackrf_error_name ( rc ));
2015-09-24 02:50:24 +02:00
}
else
{
2015-09-27 07:37:15 +02:00
qDebug () << "HackRFInput:applySettings: VGA gain set to " << m_settings . m_vgaGain ;
2015-09-24 02:50:24 +02:00
}
}
}
2017-01-08 02:48:01 +01:00
if (( m_settings . m_bandwidth != settings . m_bandwidth ) || force )
2015-09-24 02:50:24 +02:00
{
2017-01-08 04:13:20 +01:00
m_settings . m_bandwidth = settings . m_bandwidth ;
if ( m_dev != 0 )
2015-09-24 02:50:24 +02:00
{
2017-05-26 17:42:57 +02:00
uint32_t bw_index = hackrf_compute_baseband_filter_bw_round_down_lt ( m_settings . m_bandwidth + 1 ); // +1 so the round down to lower than yields desired bandwidth
2015-09-27 07:37:15 +02:00
rc = ( hackrf_error ) hackrf_set_baseband_filter_bandwidth ( m_dev , bw_index );
2015-09-24 02:50:24 +02:00
2015-09-27 07:37:15 +02:00
if ( rc != HACKRF_SUCCESS )
2015-09-24 02:50:24 +02:00
{
2015-09-27 07:37:15 +02:00
qDebug ( "HackRFInput::applySettings: hackrf_set_baseband_filter_bandwidth failed: %s" , hackrf_error_name ( rc ));
2015-09-24 02:50:24 +02:00
}
else
{
2017-01-08 02:48:01 +01:00
qDebug () << "HackRFInput:applySettings: Baseband BW filter set to " << m_settings . m_bandwidth << " Hz" ;
2015-09-24 02:50:24 +02:00
}
}
}
if (( m_settings . m_biasT != settings . m_biasT ) || force )
{
m_settings . m_biasT = settings . m_biasT ;
if ( m_dev != 0 )
{
2015-09-27 07:37:15 +02:00
rc = ( hackrf_error ) hackrf_set_antenna_enable ( m_dev , ( m_settings . m_biasT ? 1 : 0 ));
2015-09-24 02:50:24 +02:00
2015-09-27 07:37:15 +02:00
if ( rc != HACKRF_SUCCESS )
2015-09-24 02:50:24 +02:00
{
2015-09-27 11:27:02 +02:00
qDebug ( "HackRFInput::applySettings: hackrf_set_antenna_enable failed: %s" , hackrf_error_name ( rc ));
2015-09-24 02:50:24 +02:00
}
else
{
2015-09-27 07:37:15 +02:00
qDebug () << "HackRFInput:applySettings: bias tee set to " << m_settings . m_biasT ;
2015-09-24 02:50:24 +02:00
}
}
}
2015-09-27 11:27:02 +02:00
if (( m_settings . m_lnaExt != settings . m_lnaExt ) || force )
{
m_settings . m_lnaExt = settings . m_lnaExt ;
if ( m_dev != 0 )
{
rc = ( hackrf_error ) hackrf_set_amp_enable ( m_dev , ( m_settings . m_lnaExt ? 1 : 0 ));
if ( rc != HACKRF_SUCCESS )
{
qDebug ( "HackRFInput::applySettings: hackrf_set_amp_enable failed: %s" , hackrf_error_name ( rc ));
}
else
{
qDebug () << "HackRFInput:applySettings: extra LNA set to " << m_settings . m_lnaExt ;
}
}
}
2015-09-24 02:50:24 +02:00
if ( forwardChange )
{
int sampleRate = devSampleRate / ( 1 << m_settings . m_log2Decim );
DSPSignalNotification * notif = new DSPSignalNotification ( sampleRate , m_settings . m_centerFrequency );
2016-05-16 02:14:36 +02:00
m_deviceAPI -> getDeviceInputMessageQueue () -> push ( notif );
2015-09-24 02:50:24 +02:00
}
2017-07-20 23:34:12 +02:00
m_settings . m_linkTxFrequency = settings . m_linkTxFrequency ;
2017-01-08 02:48:01 +01:00
qDebug () << "HackRFInput::applySettings: center freq: " << m_settings . m_centerFrequency << " Hz"
<< " device center freq: " << deviceCenterFrequency << " Hz"
2017-04-01 13:08:41 +02:00
<< " device sample rate: " << m_settings . m_devSampleRate << "S/s"
<< " Actual sample rate: " << m_settings . m_devSampleRate / ( 1 << m_settings . m_log2Decim ) << "S/s" ;
2017-01-08 02:48:01 +01:00
2015-09-24 02:50:24 +02:00
return true ;
}
2017-01-07 11:24:09 +01:00
//hackrf_device *HackRFInput::open_hackrf_from_sequence(int sequence)
//{
// hackrf_device_list_t *hackrf_devices = hackrf_device_list();
// hackrf_device *hackrf_ptr;
// hackrf_error rc;
//
// rc = (hackrf_error) hackrf_device_list_open(hackrf_devices, sequence, &hackrf_ptr);
//
// if (rc == HACKRF_SUCCESS)
// {
// return hackrf_ptr;
// }
// else
// {
// return 0;
// }
//}