kopia lustrzana https://github.com/ogre/habdec
415 wiersze
9.2 KiB
C++
Executable File
415 wiersze
9.2 KiB
C++
Executable File
/*
|
|
|
|
Copyright 2018 Michal Fratczak
|
|
|
|
This file is part of habdec.
|
|
|
|
habdec 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, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
habdec 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 for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with habdec. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include "IQSource_SoapySDR.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <stdexcept>
|
|
|
|
#include <SoapySDR/Device.hpp>
|
|
#include <SoapySDR/Formats.hpp>
|
|
#include <SoapySDR/Errors.hpp>
|
|
|
|
namespace habdec
|
|
{
|
|
|
|
bool IQSource_SoapySDR::start()
|
|
{
|
|
if(!p_device_)
|
|
return false;
|
|
|
|
int result = 0;
|
|
if(!b_is_running_)
|
|
result = p_device_->activateStream(p_stream_);
|
|
|
|
if(result)
|
|
{
|
|
std::cout<<"IQSource_SoapySDR::start error. "<<SoapySDR::errToStr(result)<<std::endl;
|
|
return false;
|
|
}
|
|
|
|
b_is_running_ = true;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool IQSource_SoapySDR::stop()
|
|
{
|
|
if(!p_device_)
|
|
return false;
|
|
|
|
int result = 0;
|
|
if(b_is_running_)
|
|
result = p_device_->deactivateStream(p_stream_);
|
|
|
|
if(result)
|
|
{
|
|
std::cout<<"IQSource_SoapySDR::stop error. "<<SoapySDR::errToStr(result)<<std::endl;
|
|
return false;
|
|
}
|
|
|
|
b_is_running_ = false;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool IQSource_SoapySDR::isRunning() const
|
|
{
|
|
if(!p_device_)
|
|
return false;
|
|
|
|
return b_is_running_;
|
|
}
|
|
|
|
|
|
size_t IQSource_SoapySDR::count() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
size_t IQSource_SoapySDR::get(void* p_data, const size_t i_count)
|
|
{
|
|
if(!p_device_)
|
|
{
|
|
std::cout<<"p_device_ == 0"<<std::endl;
|
|
return 0;
|
|
}
|
|
|
|
if(!p_stream_)
|
|
{
|
|
std::cout<<"p_stream_ == 0"<<std::endl;
|
|
return 0;
|
|
}
|
|
|
|
if(!isRunning())
|
|
{
|
|
std::cout<<"Not Running."<<std::endl;
|
|
return 0;
|
|
}
|
|
|
|
// const size_t buffs_size = 1;
|
|
void* buffs[1] = { reinterpret_cast<void*>(p_data) };
|
|
int reveice_flags = 0;
|
|
long long time_ns = 0;
|
|
const int result = p_device_->readStream(p_stream_, buffs, i_count, reveice_flags, time_ns);
|
|
|
|
if(result<0)
|
|
{
|
|
std::cout<<"IQSource_SoapySDR::get error."<<SoapySDR::errToStr(result)<<std::endl;
|
|
return 0;
|
|
}
|
|
|
|
return static_cast<size_t>(result);
|
|
}
|
|
|
|
|
|
double IQSource_SoapySDR::samplingRate() const
|
|
{
|
|
return sampling_rate_;
|
|
}
|
|
|
|
|
|
IQSource_SoapySDR::~IQSource_SoapySDR()
|
|
{
|
|
if(p_device_)
|
|
{
|
|
stop();
|
|
p_device_->closeStream(p_stream_);
|
|
//SoapySDR::Device::unmake(p_device_.get());
|
|
}
|
|
}
|
|
|
|
|
|
bool IQSource_SoapySDR::init()
|
|
{
|
|
p_device_.reset( SoapySDR::Device::make(soapysdr_kwargs_) );
|
|
|
|
if(!p_device_)
|
|
return false;
|
|
|
|
using namespace std;
|
|
|
|
cout<<"IQSource_SoapySDR::init"<<endl;
|
|
|
|
const string driver_key = p_device_->getDriverKey();
|
|
cout<<'\t'<<"driver_key "<<driver_key<<endl;
|
|
|
|
hwinfo_hwkey_ = p_device_->getHardwareKey();
|
|
|
|
const auto serial_it = soapysdr_kwargs_.find("serial");
|
|
if(serial_it != soapysdr_kwargs_.end())
|
|
hwinfo_serial_ = serial_it->second;
|
|
|
|
// hw info
|
|
// cout<<'\t'<<"hw_info:"<<endl;
|
|
const SoapySDR::Kwargs hw_info = p_device_->getHardwareInfo();
|
|
for(const auto& it : hw_info)
|
|
{
|
|
// cout<<"\t\tproperty:: "<<it.first<<":"<<it.second<<endl;
|
|
const string property = it.first;
|
|
// cout<<"Prop "<<property<<endl;
|
|
|
|
try {
|
|
if(property == "device_id")
|
|
{
|
|
hwinfo_device_id_ = std::stof(it.second);
|
|
}
|
|
}
|
|
catch(std::invalid_argument& e) {
|
|
cout<<"Failed argument conversion for "<<property<<endl;
|
|
}
|
|
}
|
|
|
|
// gains
|
|
hwinfo_gains_.clear();
|
|
for(const auto gain : p_device_->listGains(SOAPY_SDR_RX,0))
|
|
hwinfo_gains_.push_back(gain);
|
|
|
|
// freq range
|
|
const SoapySDR::RangeList freq_range_list = p_device_->getFrequencyRange(SOAPY_SDR_RX, 0);
|
|
hwinfo_freq_min_ = freq_range_list.front().minimum();
|
|
hwinfo_freq_max_ = freq_range_list.back().maximum();
|
|
|
|
// sampling rates
|
|
hwinfo_sampling_rates_ = p_device_->listSampleRates(SOAPY_SDR_RX, 0);
|
|
sort(hwinfo_sampling_rates_.begin(), hwinfo_sampling_rates_.end());
|
|
|
|
// stream formats
|
|
hwinfo_stream_formats_.clear();
|
|
for(const auto stream_format : p_device_->getStreamFormats(SOAPY_SDR_RX, 0)) // doubles
|
|
hwinfo_stream_formats_.push_back(stream_format);
|
|
|
|
// gain range
|
|
const SoapySDR::Range gain_range = p_device_->getGainRange(SOAPY_SDR_RX, 0);
|
|
hwinfo_gain_min_ = gain_range.minimum();
|
|
hwinfo_gain_max_ = gain_range.maximum();
|
|
|
|
// init
|
|
|
|
sampling_rate_ = hwinfo_sampling_rates_.back();
|
|
if(hwinfo_hwkey_ != "Airspy")
|
|
sampling_rate_ = hwinfo_sampling_rates_[3];
|
|
p_device_->setSampleRate(SOAPY_SDR_RX, 0, sampling_rate_);
|
|
|
|
p_device_->setGain( SOAPY_SDR_RX, 0, (hwinfo_gain_max_ - hwinfo_gain_min_)/2 );
|
|
p_device_->setFrequency( SOAPY_SDR_RX, 0, 434274500 );
|
|
p_stream_ = p_device_->setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32);
|
|
|
|
|
|
// PRINT INFO
|
|
/////////////////
|
|
|
|
// hw info
|
|
cout<<'\t'<<"hw_key "<<hwinfo_hwkey_<<endl;
|
|
cout<<'\t'<<"device_id "<<hwinfo_device_id_<<endl;
|
|
cout<<'\t'<<"serial "<<hwinfo_serial_<<endl;
|
|
|
|
// gains
|
|
cout<<"\tGains:\t";
|
|
for(const auto& gain : hwinfo_gains_)
|
|
cout<<gain<<", ";
|
|
cout<<endl;
|
|
|
|
cout<<"\tGain Range: "<<hwinfo_gain_min_<<" "<<hwinfo_gain_max_<<endl;
|
|
|
|
// freq range
|
|
cout<<"\tFreq Range: "<<hwinfo_freq_min_<<" "<<hwinfo_freq_max_<<endl;
|
|
|
|
// sampling rates
|
|
cout<<"\tSampling Ranges: ";
|
|
for(const auto sampling_rate : hwinfo_sampling_rates_)
|
|
cout<<sampling_rate<<", ";
|
|
cout<<endl;
|
|
|
|
// stream formats
|
|
cout<<"\tStream Formats: ";
|
|
for(const auto stream_format : hwinfo_stream_formats_)
|
|
cout<<stream_format<<", ";
|
|
cout<<endl;
|
|
|
|
|
|
// others
|
|
|
|
// nothing for AirSpy
|
|
cout<<"\tFrontend mapping:"<<p_device_->getFrontendMapping(SOAPY_SDR_RX)<<endl;
|
|
|
|
// nothing for AirSpy
|
|
cout<<"\tBandwidths: ";
|
|
for(const auto bandwidth : p_device_->listBandwidths(SOAPY_SDR_RX, 0)) // doubles
|
|
cout<<bandwidth<<", ";
|
|
cout<<endl;
|
|
|
|
cout<<"\tHas DC Offset: "<<p_device_->hasDCOffsetMode(SOAPY_SDR_RX, 0)<<endl;
|
|
|
|
cout<<"\tHas Freq Correction: "<<p_device_->hasFrequencyCorrection(SOAPY_SDR_RX, 0)<<endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
bool IQSource_SoapySDR::setOption(const std::string& option, const void* p_data)
|
|
{
|
|
using namespace std;
|
|
|
|
void* p_data_nonconst = const_cast<void*>(p_data);
|
|
|
|
bool b_verbose = false;
|
|
|
|
if(option == "SoapySDR_Kwargs")
|
|
{
|
|
soapysdr_kwargs_ = *reinterpret_cast<SoapySDR::Kwargs*>(p_data_nonconst);
|
|
return true;
|
|
}
|
|
|
|
if(!p_device_)
|
|
{
|
|
cout<<"IQSource_SoapySDR::setOption no device initialized."<<endl;
|
|
}
|
|
|
|
if(option == "sampling_rate_double")
|
|
{
|
|
double value = *reinterpret_cast<double*>(p_data_nonconst);
|
|
cout<<"Setting "<<option<<" = "<<value<<endl;
|
|
if(p_device_)
|
|
{
|
|
p_device_->setSampleRate(SOAPY_SDR_RX, 0, value);
|
|
sampling_rate_ = p_device_->getSampleRate(SOAPY_SDR_RX, 0);
|
|
cout<<"Set "<<option<<" = "<<sampling_rate_<<endl;
|
|
}
|
|
return true;
|
|
}
|
|
else if(option == "frequency_double")
|
|
{
|
|
double value = *reinterpret_cast<double*>(p_data_nonconst);
|
|
if(p_device_)
|
|
{
|
|
if(b_verbose)
|
|
cout<<"Set "<<option<<" = "<<setprecision(12)<<value<<endl;
|
|
p_device_->setFrequency( SOAPY_SDR_RX, 0, value );
|
|
}
|
|
return true;
|
|
}
|
|
else if(option == "gain_double")
|
|
{
|
|
double value = *reinterpret_cast<double*>(p_data_nonconst);
|
|
if(p_device_)
|
|
{
|
|
p_device_->setGain( SOAPY_SDR_RX, 0, value );
|
|
if(b_verbose)
|
|
cout<<"Set "<<option<<" = "<<value<<endl;
|
|
}
|
|
return true;
|
|
}
|
|
else if(option == "biastee_double")
|
|
{
|
|
double value = *reinterpret_cast<double*>(p_data_nonconst);
|
|
if(p_device_)
|
|
{
|
|
if(b_verbose)
|
|
cout<<"Set "<<option<<" = "<<setprecision(12)<<value<<endl;
|
|
if(value)
|
|
p_device_->writeSetting("biastee", "true");
|
|
else
|
|
p_device_->writeSetting("biastee", "false");
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
cout<<"IQSource_SoapySDR::setOption error. Unknown option: "<<option<<endl;
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool IQSource_SoapySDR::getOption(const std::string& option, void* p_data)
|
|
{
|
|
using namespace std;
|
|
|
|
bool b_verbose = false;
|
|
|
|
if(!p_device_)
|
|
{
|
|
cout<<"IQSource_SoapySDR::setOption no device initialized."<<endl;
|
|
}
|
|
|
|
if(option == "sampling_rate_double")
|
|
{
|
|
*reinterpret_cast<double*>(p_data) = sampling_rate_;
|
|
if(b_verbose)
|
|
cout<<"getOption "<<option<<" "<<*reinterpret_cast<double*>(p_data)<<endl;
|
|
return true;
|
|
}
|
|
else if(option == "frequency_double")
|
|
{
|
|
if(p_device_)
|
|
{
|
|
*reinterpret_cast<double*>(p_data) = p_device_->getFrequency( SOAPY_SDR_RX, 0);
|
|
if(b_verbose)
|
|
cout<<"getOption "<<option<<" "<<*reinterpret_cast<double*>(p_data)<<endl;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
else if(option == "gain_double")
|
|
{
|
|
if(p_device_)
|
|
{
|
|
*reinterpret_cast<double*>(p_data) = p_device_->getGain( SOAPY_SDR_RX, 0 );
|
|
if(b_verbose)
|
|
cout<<"getOption "<<option<<" "<<*reinterpret_cast<double*>(p_data)<<endl;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
else if(option == "biastee_double")
|
|
{
|
|
if(p_device_)
|
|
{
|
|
double biastee_val =
|
|
p_device_->readSetting("biastee") == string("true");
|
|
*reinterpret_cast<double*>(p_data) = biastee_val;
|
|
if(b_verbose)
|
|
cout<<"getOption "<<option<<" "<<biastee_val<<endl;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
cout<<"IQSource_SoapySDR::getOption error. Unknown option: "<<option<<endl;
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
} // namespace habdec
|