mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 21:20:31 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			351 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			351 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
///////////////////////////////////////////////////////////////////////////////////
 | 
						|
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
 | 
						|
// written by Christian Daniel                                                   //
 | 
						|
// Copyright (C) 2013 by Dimitri Stolnikov <horiz0n@gmx.net>                     //
 | 
						|
//                                                                               //
 | 
						|
// 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/>.          //
 | 
						|
///////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
#include <string.h>
 | 
						|
#include <errno.h>
 | 
						|
#include "util/simpleserializer.h"
 | 
						|
#include "gnuradioinput.h"
 | 
						|
#include "gnuradiothread.h"
 | 
						|
#include "gnuradiogui.h"
 | 
						|
 | 
						|
MESSAGE_CLASS_DEFINITION(GNURadioInput::MsgConfigureGNURadio, Message)
 | 
						|
MESSAGE_CLASS_DEFINITION(GNURadioInput::MsgReportGNURadio, Message)
 | 
						|
 | 
						|
GNURadioInput::Settings::Settings() :
 | 
						|
	m_args(""),
 | 
						|
	m_freqCorr(0),
 | 
						|
	m_sampRate(0),
 | 
						|
	m_antenna(""),
 | 
						|
	m_dcoff("Keep"),
 | 
						|
	m_iqbal("Keep"),
 | 
						|
	m_bandwidth(0)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void GNURadioInput::Settings::resetToDefaults()
 | 
						|
{
 | 
						|
	m_args = "";
 | 
						|
	m_sampRate = 0;
 | 
						|
	m_freqCorr = 0;
 | 
						|
	m_antenna = "";
 | 
						|
	m_dcoff = "Keep";
 | 
						|
	m_iqbal = "Keep";
 | 
						|
	m_bandwidth = 0;
 | 
						|
}
 | 
						|
 | 
						|
QByteArray GNURadioInput::Settings::serialize() const
 | 
						|
{
 | 
						|
	SimpleSerializer s(1);
 | 
						|
	s.writeString(1, m_args);
 | 
						|
	s.writeDouble(2, m_freqCorr);
 | 
						|
	s.writeDouble(3, m_sampRate);
 | 
						|
	s.writeString(4, m_antenna);
 | 
						|
	s.writeString(5, m_dcoff);
 | 
						|
	s.writeString(6, m_iqbal);
 | 
						|
	s.writeDouble(7, m_bandwidth);
 | 
						|
 | 
						|
	for (int i=0; i < m_namedGains.size(); i++)
 | 
						|
	{
 | 
						|
		s.writeDouble(100+i, m_namedGains[i].second);
 | 
						|
	}
 | 
						|
 | 
						|
	return s.final();
 | 
						|
}
 | 
						|
 | 
						|
bool GNURadioInput::Settings::deserialize(const QByteArray& data)
 | 
						|
{
 | 
						|
	SimpleDeserializer d(data);
 | 
						|
 | 
						|
	if(!d.isValid()) {
 | 
						|
		resetToDefaults();
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	if(d.getVersion() == 1) {
 | 
						|
		d.readString(1, &m_args, "");
 | 
						|
		d.readDouble(2, &m_freqCorr, 0);
 | 
						|
		d.readDouble(3, &m_sampRate, 0);
 | 
						|
		d.readString(4, &m_antenna, "");
 | 
						|
		d.readString(5, &m_dcoff, "Keep");
 | 
						|
		d.readString(6, &m_iqbal, "Keep");
 | 
						|
		d.readDouble(7, &m_bandwidth, 0);
 | 
						|
 | 
						|
		for (int i = 0; i < m_namedGains.size(); i++)
 | 
						|
		{
 | 
						|
			double value;
 | 
						|
			d.readDouble(100+i, &value, 0);
 | 
						|
			m_namedGains[i].second = value;
 | 
						|
		}
 | 
						|
 | 
						|
		return true;
 | 
						|
	} else {
 | 
						|
		resetToDefaults();
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
GNURadioInput::GNURadioInput(MessageQueue* msgQueueToGUI) :
 | 
						|
	SampleSource(msgQueueToGUI),
 | 
						|
	m_settings(),
 | 
						|
	m_GnuradioThread(NULL),
 | 
						|
	m_deviceDescription()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
GNURadioInput::~GNURadioInput()
 | 
						|
{
 | 
						|
	stopInput();
 | 
						|
}
 | 
						|
 | 
						|
bool GNURadioInput::startInput(int device)
 | 
						|
{
 | 
						|
	double freqMin = 0, freqMax = 0, freqCorr = 0;
 | 
						|
	std::vector< std::pair< QString, std::vector<double> > > namedGains;
 | 
						|
	std::vector< double > sampRates;
 | 
						|
	std::vector< QString > antennas;
 | 
						|
	std::vector< double > bandwidths;
 | 
						|
 | 
						|
	QMutexLocker mutexLocker(&m_mutex);
 | 
						|
 | 
						|
	if(m_GnuradioThread != NULL)
 | 
						|
		stopInput();
 | 
						|
 | 
						|
	if(!m_sampleFifo.setSize( 2 * 1024 * 1024 )) {
 | 
						|
		qCritical("Could not allocate SampleFifo");
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	m_deviceDescription = m_settings.m_args;
 | 
						|
 | 
						|
	// pass device arguments from the gui
 | 
						|
	m_GnuradioThread = new GnuradioThread(m_settings.m_args, &m_sampleFifo);
 | 
						|
	if(m_GnuradioThread == NULL) {
 | 
						|
		qFatal("out of memory");
 | 
						|
		goto failed;
 | 
						|
	}
 | 
						|
	m_GnuradioThread->startWork();
 | 
						|
 | 
						|
	mutexLocker.unlock();
 | 
						|
	//applySettings(m_generalSettings, m_settings, true);
 | 
						|
 | 
						|
	if(m_GnuradioThread != NULL) {
 | 
						|
		osmosdr::source::sptr radio = m_GnuradioThread->radio();
 | 
						|
 | 
						|
		try {
 | 
						|
			osmosdr::freq_range_t freq_rage = radio->get_freq_range();
 | 
						|
			freqMin = freq_rage.start();
 | 
						|
			freqMax = freq_rage.stop();
 | 
						|
		} catch ( std::exception &ex ) {
 | 
						|
			qDebug("%s", ex.what());
 | 
						|
		}
 | 
						|
 | 
						|
		freqCorr = radio->get_freq_corr();
 | 
						|
 | 
						|
		namedGains.clear();
 | 
						|
		m_settings.m_namedGains.clear();
 | 
						|
		std::vector< std::string > gain_names = radio->get_gain_names();
 | 
						|
		for ( uint i = 0; i < gain_names.size(); i++ )
 | 
						|
		{
 | 
						|
			std::string gain_name = gain_names[i];
 | 
						|
 | 
						|
			try {
 | 
						|
				std::vector< double > gain_values = \
 | 
						|
						radio->get_gain_range( gain_name ).values();
 | 
						|
 | 
						|
				std::pair< QString, std::vector<double> > pair( gain_name.c_str(),
 | 
						|
										gain_values );
 | 
						|
 | 
						|
				namedGains.push_back( pair );
 | 
						|
 | 
						|
				QPair< QString, double > pair2( gain_name.c_str(), 0 );
 | 
						|
 | 
						|
				m_settings.m_namedGains.push_back( pair2 );
 | 
						|
			} catch ( std::exception &ex ) {
 | 
						|
				qDebug("%s", ex.what());
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		try {
 | 
						|
			sampRates = radio->get_sample_rates().values();
 | 
						|
		} catch ( std::exception &ex ) {
 | 
						|
			qDebug("%s", ex.what());
 | 
						|
		}
 | 
						|
 | 
						|
		antennas.clear();
 | 
						|
		std::vector< std::string > ant = radio->get_antennas();
 | 
						|
		for ( uint i = 0; i < ant.size(); i++ )
 | 
						|
			antennas.push_back( QString( ant[i].c_str() ) );
 | 
						|
 | 
						|
		m_dcoffs.clear();
 | 
						|
		m_dcoffs.push_back( "Off" );
 | 
						|
		m_dcoffs.push_back( "Keep" );
 | 
						|
		m_dcoffs.push_back( "Auto" );
 | 
						|
 | 
						|
		m_iqbals.clear();
 | 
						|
		m_iqbals.push_back( "Off" );
 | 
						|
		m_iqbals.push_back( "Keep" );
 | 
						|
		m_iqbals.push_back( "Auto" );
 | 
						|
 | 
						|
		try {
 | 
						|
			bandwidths = radio->get_bandwidth_range().values();
 | 
						|
		} catch ( std::exception &ex ) {
 | 
						|
			qDebug("%s", ex.what());
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	qDebug("GnuradioInput: start");
 | 
						|
	MsgReportGNURadio::create(freqMin, freqMax, freqCorr, namedGains,
 | 
						|
				  sampRates, antennas, m_dcoffs, m_iqbals,
 | 
						|
				  bandwidths)
 | 
						|
			->submit(m_guiMessageQueue);
 | 
						|
 | 
						|
	return true;
 | 
						|
 | 
						|
failed:
 | 
						|
	stopInput();
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
void GNURadioInput::stopInput()
 | 
						|
{
 | 
						|
	QMutexLocker mutexLocker(&m_mutex);
 | 
						|
 | 
						|
	if(m_GnuradioThread != NULL) {
 | 
						|
		m_GnuradioThread->stopWork();
 | 
						|
		delete m_GnuradioThread;
 | 
						|
		m_GnuradioThread = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	m_deviceDescription.clear();
 | 
						|
}
 | 
						|
 | 
						|
const QString& GNURadioInput::getDeviceDescription() const
 | 
						|
{
 | 
						|
	return m_deviceDescription;
 | 
						|
}
 | 
						|
 | 
						|
int GNURadioInput::getSampleRate() const
 | 
						|
{
 | 
						|
	return m_settings.m_sampRate;
 | 
						|
}
 | 
						|
 | 
						|
quint64 GNURadioInput::getCenterFrequency() const
 | 
						|
{
 | 
						|
	return m_generalSettings.m_centerFrequency;
 | 
						|
}
 | 
						|
 | 
						|
bool GNURadioInput::handleMessage(Message* message)
 | 
						|
{
 | 
						|
	if(MsgConfigureGNURadio::match(message)) {
 | 
						|
		MsgConfigureGNURadio* conf = (MsgConfigureGNURadio*)message;
 | 
						|
		if(!applySettings(conf->getGeneralSettings(), conf->getSettings(), false))
 | 
						|
			qDebug("Gnuradio config error");
 | 
						|
		return true;
 | 
						|
	} else {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
bool GNURadioInput::applySettings(const GeneralSettings& generalSettings,
 | 
						|
				  const Settings& settings,
 | 
						|
				  bool force)
 | 
						|
{
 | 
						|
	QMutexLocker mutexLocker(&m_mutex);
 | 
						|
 | 
						|
	m_settings.m_args = settings.m_args;
 | 
						|
 | 
						|
	if ( NULL == m_GnuradioThread )
 | 
						|
		return true;
 | 
						|
 | 
						|
	osmosdr::source::sptr radio = m_GnuradioThread->radio();
 | 
						|
 | 
						|
	try {
 | 
						|
 | 
						|
		if((m_settings.m_freqCorr != settings.m_freqCorr) || force) {
 | 
						|
			m_settings.m_freqCorr = settings.m_freqCorr;
 | 
						|
			radio->set_freq_corr( m_settings.m_freqCorr );
 | 
						|
		}
 | 
						|
 | 
						|
		if((m_generalSettings.m_centerFrequency != generalSettings.m_centerFrequency) || force) {
 | 
						|
			m_generalSettings.m_centerFrequency = generalSettings.m_centerFrequency;
 | 
						|
			radio->set_center_freq( m_generalSettings.m_centerFrequency );
 | 
						|
		}
 | 
						|
 | 
						|
		for ( int i = 0; i < settings.m_namedGains.size(); i++ )
 | 
						|
		{
 | 
						|
			if((m_settings.m_namedGains[i].second != settings.m_namedGains[i].second) || force) {
 | 
						|
				m_settings.m_namedGains[i].second = settings.m_namedGains[i].second;
 | 
						|
				radio->set_gain( settings.m_namedGains[i].second,
 | 
						|
						 settings.m_namedGains[i].first.toStdString() );
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if((m_settings.m_sampRate != settings.m_sampRate) || force) {
 | 
						|
			m_settings.m_sampRate = settings.m_sampRate;
 | 
						|
			radio->set_sample_rate( m_settings.m_sampRate );
 | 
						|
		}
 | 
						|
 | 
						|
		if((m_settings.m_antenna != settings.m_antenna) || force) {
 | 
						|
			m_settings.m_antenna = settings.m_antenna;
 | 
						|
			radio->set_antenna( m_settings.m_antenna.toStdString() );
 | 
						|
		}
 | 
						|
 | 
						|
		/* Removed as it is incapable of handling it correctly (initialize at "Keep").
 | 
						|
		 * For BladeRF it must be done via bladerRF-cli */
 | 
						|
		if((m_settings.m_dcoff != settings.m_dcoff) || force) {
 | 
						|
			m_settings.m_dcoff = settings.m_dcoff;
 | 
						|
 | 
						|
			for ( uint i = 0; i < m_dcoffs.size(); i++ )
 | 
						|
			{
 | 
						|
				if ( m_dcoffs[i] !=  m_settings.m_dcoff )
 | 
						|
					continue;
 | 
						|
 | 
						|
				//radio->set_dc_offset_mode( i );
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if((m_settings.m_iqbal != settings.m_iqbal) || force) {
 | 
						|
			m_settings.m_iqbal = settings.m_iqbal;
 | 
						|
 | 
						|
			for ( uint i = 0; i < m_iqbals.size(); i++ )
 | 
						|
			{
 | 
						|
				if ( m_iqbals[i] !=  m_settings.m_iqbal )
 | 
						|
					continue;
 | 
						|
 | 
						|
				//radio->set_iq_balance_mode( i );
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if((m_settings.m_bandwidth != settings.m_bandwidth) ||
 | 
						|
				(0.0f == settings.m_bandwidth) || force) {
 | 
						|
			m_settings.m_bandwidth = settings.m_bandwidth;
 | 
						|
			/* setting the BW to 0.0 triggers automatic bandwidth
 | 
						|
			 * selection when supported by device */
 | 
						|
			radio->set_bandwidth( m_settings.m_bandwidth );
 | 
						|
		}
 | 
						|
 | 
						|
	} catch ( std::exception &ex ) {
 | 
						|
		qDebug("%s", ex.what());
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 |