satdump/plugins/sdr_sources/usrp_sdr_support/usrp_sdr.cpp

283 lines
7.9 KiB
C++

#include "usrp_sdr.h"
void USRPSource::set_gains()
{
if (!is_started)
return;
usrp_device->set_rx_gain(gain, channel);
logger->debug("Set USRP gain to %f", gain);
}
void USRPSource::open_sdr()
{
uhd::device_addrs_t devlist = uhd::device::find(uhd::device_addr_t());
usrp_device = uhd::usrp::multi_usrp::make(devlist[std::stoi(d_sdr_id)]);
// uhd::meta_range_t master_clock_range = usrp_device->get_master_clock_rate_range();
// usrp_device->set_master_clock_rate(master_clock_range.stop());
uhd::usrp::subdev_spec_t sub_boards = usrp_device->get_rx_subdev_spec();
channel_option_str = "";
for (int i = 0; i < (int)sub_boards.size(); i++)
{
logger->trace("USRP has " + usrp_device->get_rx_subdev_name(i) + " in slot " + sub_boards[i].db_name);
channel_option_str += usrp_device->get_rx_subdev_name(i) + " (" + sub_boards[i].db_name + ")" + '\0';
}
}
void USRPSource::open_channel()
{
if (channel >= (int)usrp_device->get_rx_num_channels())
throw satdump_exception("Channel " + std::to_string(channel) + " is invalid!");
logger->info("Using USRP channel %d", channel);
if (usrp_device->get_master_clock_rate_range().start() != usrp_device->get_master_clock_rate_range().stop())
use_device_rates = true;
std::vector<double> available_samplerates;
// Preserve current samplerate selection before updating the list
double current_samplerate = samplerate_widget.get_value();
if (use_device_rates)
{
// Get samplerates
uhd::meta_range_t dev_samplerates = usrp_device->get_master_clock_rate_range();
available_samplerates.clear();
for (auto &sr : dev_samplerates)
{
if (sr.step() == 0 && sr.start() == sr.stop())
{
available_samplerates.push_back(sr.start());
}
else if (sr.step() == 0)
{
for (double s = std::max(sr.start(), 1e6); s < sr.stop(); s += 1e6)
available_samplerates.push_back(s);
available_samplerates.push_back(sr.stop());
}
else
{
for (double s = sr.start(); s <= sr.stop(); s += sr.step())
available_samplerates.push_back(s);
}
}
}
else
{
// Get samplerates
uhd::meta_range_t dev_samplerates = usrp_device->get_rx_rates(channel);
available_samplerates.clear();
for (auto &sr : dev_samplerates)
{
if (sr.step() == 0 || sr.start() == sr.stop())
{
available_samplerates.push_back(sr.start());
}
else
{
for (double s = sr.start(); s <= sr.stop(); s += sr.step())
available_samplerates.push_back(s);
}
}
}
samplerate_widget.set_list(available_samplerates, false);
// Restore the previously selected samplerate if it's still available
samplerate_widget.set_value(current_samplerate, 0);
// Get gain range
gain_range = usrp_device->get_rx_gain_range(channel);
usrp_antennas = usrp_device->get_rx_antennas(channel);
antenna_option_str = "";
for (int i = 0; i < (int)usrp_antennas.size(); i++)
{
antenna_option_str += usrp_antennas[i] + '\0';
logger->trace("USRP has antenna option %s", usrp_antennas[i].c_str());
}
}
void USRPSource::set_settings(nlohmann::json settings)
{
d_settings = settings;
channel = getValueOrDefault(d_settings["channel"], channel);
antenna = getValueOrDefault(d_settings["antenna"], antenna);
gain = getValueOrDefault(d_settings["gain"], gain);
bit_depth = getValueOrDefault(d_settings["bit_depth"], bit_depth);
if (bit_depth == 8)
selected_bit_depth = 0;
else if (bit_depth == 16)
selected_bit_depth = 1;
if (is_started)
{
set_gains();
}
}
nlohmann::json USRPSource::get_settings()
{
d_settings["channel"] = channel;
d_settings["antenna"] = antenna;
d_settings["gain"] = gain;
d_settings["bit_depth"] = bit_depth;
return d_settings;
}
void USRPSource::open()
{
open_sdr();
is_open = true;
open_channel();
usrp_device.reset();
}
void USRPSource::start()
{
DSPSampleSource::start();
open_sdr();
open_channel();
uint64_t current_samplerate = samplerate_widget.get_value();
logger->debug("Set USRP samplerate to " + std::to_string(current_samplerate));
if (use_device_rates)
usrp_device->set_master_clock_rate(current_samplerate);
usrp_device->set_rx_rate(current_samplerate, channel);
usrp_device->set_rx_bandwidth(current_samplerate, channel);
if (antenna >= (int)usrp_device->get_rx_antennas(channel).size())
throw satdump_exception("Antenna " + std::to_string(antenna) + " is invalid!");
usrp_device->set_rx_antenna(usrp_antennas[antenna], channel);
is_started = true;
set_frequency(d_frequency);
set_gains();
uhd::stream_args_t sargs;
sargs.channels.clear();
sargs.channels.push_back(channel);
sargs.cpu_format = "fc32";
if (bit_depth == 8)
sargs.otw_format = "sc8";
else if (bit_depth == 16)
sargs.otw_format = "sc16";
usrp_streamer = usrp_device->get_rx_stream(sargs);
thread_should_run = true;
work_thread = std::thread(&USRPSource::mainThread, this);
usrp_streamer->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
}
void USRPSource::stop()
{
thread_should_run = false;
logger->info("Waiting for the thread...");
if (is_started)
output_stream->stopWriter();
if (work_thread.joinable())
work_thread.join();
logger->info("Thread stopped");
if (is_started)
{
usrp_streamer->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
usrp_streamer.reset();
usrp_device.reset();
}
is_started = false;
}
void USRPSource::close()
{
is_open = false;
}
void USRPSource::set_frequency(uint64_t frequency)
{
if (is_started)
{
usrp_device->set_rx_freq(frequency, channel);
logger->debug("Set USRP frequency to %d", frequency);
}
DSPSampleSource::set_frequency(frequency);
}
void USRPSource::drawControlUI()
{
if (is_started)
RImGui::beginDisabled();
if (RImGui::Combo("Channel", &channel, channel_option_str.c_str()) && is_open)
{
open_sdr();
open_channel();
usrp_streamer.reset();
usrp_device.reset();
}
RImGui::Combo("Antenna", &antenna, antenna_option_str.c_str());
samplerate_widget.render();
if (RImGui::Combo("Bit depth", &selected_bit_depth, "8-bits\0"
"16-bits\0"))
{
if (selected_bit_depth == 0)
bit_depth = 8;
else if (selected_bit_depth == 1)
bit_depth = 16;
}
if (is_started)
RImGui::endDisabled();
// Gain settings
if (is_open)
{
if (RImGui::SteppedSliderFloat("Gain", &gain, gain_range.start(), gain_range.stop()))
set_gains();
}
else // Defaults for using UI when device is not attached (config export)
RImGui::SteppedSliderFloat("Gain", &gain, 0, 60);
}
void USRPSource::set_samplerate(uint64_t samplerate)
{
if (!samplerate_widget.set_value(samplerate, 0))
throw satdump_exception("Unsupported samplerate : " + std::to_string(samplerate) + "!");
}
uint64_t USRPSource::get_samplerate()
{
return samplerate_widget.get_value();
}
std::vector<dsp::SourceDescriptor> USRPSource::getAvailableSources()
{
std::vector<dsp::SourceDescriptor> results;
uhd::device_addrs_t devlist = uhd::device::find(uhd::device_addr_t());
uint64_t i = 0;
for (const uhd::device_addr_t &dev : devlist)
{
std::string type = dev.has_key("product") ? dev["product"] : dev["type"];
results.push_back({"usrp", "USRP " + type + " " + dev["serial"], std::to_string(i)});
i++;
}
return results;
}