Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions Registration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,49 +31,77 @@
//the tuner is cached because the device cannot be opened twice in the same process,
//and we require that findRTLSDR() yield the same results for SoapySDR device cache.
//if another process attempts to find an open rtlsdr, it will be marked unavailable
static std::string get_tuner(const std::string &serial, const size_t deviceIndex)
// USB indexes identify receivers on every platform, including devices with
// duplicate or empty serials. Only tuner metadata probing is browser-specific:
// native libusb can safely open devices during discovery, while WebUSB cannot.
#ifndef __EMSCRIPTEN__
static std::string get_tuner(const size_t deviceIndex)
{
static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);

static std::map<std::string, std::string> cache;
auto it = cache.find(serial);
static std::map<size_t, std::string> cache;
auto it = cache.find(deviceIndex);
if (it != cache.end()) return it->second;

rtlsdr_dev_t *devTest;
if (rtlsdr_open(&devTest, deviceIndex) != 0) return "unavailable";
const auto tuner = SoapyRTLSDR::rtlTunerToString(rtlsdr_get_tuner_type(devTest));
rtlsdr_close(devTest);
cache[serial] = tuner;
cache[deviceIndex] = tuner;
return tuner;
}
#endif

static std::vector<SoapySDR::Kwargs> findRTLSDR(const SoapySDR::Kwargs &args)
{
std::vector<SoapySDR::Kwargs> results;

char manufact[256], product[256], serial[256];
char manufact[256] = {}, product[256] = {}, serial[256] = {};

const size_t this_count = rtlsdr_get_device_count();

for (size_t i = 0; i < this_count; i++)
{
#ifdef __EMSCRIPTEN__
// Do not open every receiver merely to populate discovery metadata.
// WebUSB serializes asynchronous access to each authorized USBDevice,
// so probing one active or unresponsive receiver can block the others.
// Keep explicit legacy serial filtering, but use the cross-platform
// USB index as the normal device identity.
if (args.count("serial") != 0 &&
rtlsdr_get_device_usb_strings(i, manufact, product, serial) != 0)
{
SoapySDR_logf(SOAPY_SDR_ERROR, "rtlsdr_get_device_usb_strings(%zu) failed", i);
continue;
}
#else
if (rtlsdr_get_device_usb_strings(i, manufact, product, serial) != 0)
{
SoapySDR_logf(SOAPY_SDR_ERROR, "rtlsdr_get_device_usb_strings(%zu) failed", i);
continue;
}
SoapySDR_logf(SOAPY_SDR_DEBUG, "\tManufacturer: %s, Product Name: %s, Serial: %s", manufact, product, serial);
#endif

const std::string index = std::to_string(i);

// Index filtering works on every platform; serial remains a
// compatibility path for existing device strings.
if (args.count("index") != 0 and args.at("index") != index) continue;
if (args.count("serial") != 0 and args.at("serial") != serial) continue;

SoapySDR::Kwargs devInfo;
#ifdef __EMSCRIPTEN__
devInfo["label"] = std::string(rtlsdr_get_device_name(i)) + " [USB index " + index + "]";
#else
devInfo["label"] = std::string(rtlsdr_get_device_name(i)) + " :: " + serial;
devInfo["product"] = product;
devInfo["serial"] = serial;
devInfo["manufacturer"] = manufact;
devInfo["tuner"] = get_tuner(serial, i);

//filtering by serial
if (args.count("serial") != 0 and args.at("serial") != serial) continue;
devInfo["tuner"] = get_tuner(i);
#endif
devInfo["index"] = index;

results.push_back(devInfo);
}
Expand Down
44 changes: 37 additions & 7 deletions Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <SoapySDR/Time.hpp>
#include <algorithm>
#include <cstring>
#include <limits>

SoapyRTLSDR::SoapyRTLSDR(const SoapySDR::Kwargs &args):
deviceId(-1),
Expand Down Expand Up @@ -60,20 +61,50 @@ SoapyRTLSDR::SoapyRTLSDR(const SoapySDR::Kwargs &args):
{
if (args.count("label") != 0) SoapySDR_logf(SOAPY_SDR_INFO, "Opening %s...", args.at("label").c_str());

//if a serial is not present, then findRTLSDR had zero devices enumerated
if (args.count("serial") == 0) throw std::runtime_error("No RTL-SDR devices found!");
// Prefer the enumerated USB index on every platform so receivers with
// duplicate or empty serial descriptors can still be selected uniquely.
// Retain serial lookup for compatibility with existing configurations.
if (args.count("index") != 0)
{
const auto index = args.at("index");
size_t parsedCharacters = 0;
unsigned long parsedIndex = 0;
try
{
parsedIndex = std::stoul(index, &parsedCharacters);
}
catch (const std::exception &)
{
throw std::runtime_error("Invalid RTL-SDR device index: " + index);
}

const auto serial = args.at("serial");
deviceId = rtlsdr_get_index_by_serial(serial.c_str());
if (deviceId < 0) throw std::runtime_error("rtlsdr_get_index_by_serial("+serial+") - " + std::to_string(deviceId));
if (parsedCharacters != index.size() ||
parsedIndex > std::numeric_limits<int>::max() ||
parsedIndex >= rtlsdr_get_device_count())
{
throw std::runtime_error("Invalid RTL-SDR device index: " + index);
}
deviceId = static_cast<int>(parsedIndex);
}
else if (args.count("serial") != 0)
{
const auto serial = args.at("serial");
deviceId = rtlsdr_get_index_by_serial(serial.c_str());
if (deviceId < 0) throw std::runtime_error("rtlsdr_get_index_by_serial("+serial+") - " + std::to_string(deviceId));
}
else
{
throw std::runtime_error("No RTL-SDR device index or serial specified!");
}

if (args.count("tuner") != 0) tunerType = rtlStringToTuner(args.at("tuner"));
SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR Tuner type: %s", rtlTunerToString(tunerType).c_str());

SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR opening device %d", deviceId);
if (rtlsdr_open(&dev, deviceId) != 0) {
throw std::runtime_error("Unable to open RTL-SDR device");
}
tunerType = rtlsdr_get_tuner_type(dev);
SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR Tuner type: %s", rtlTunerToString(tunerType).c_str());

//extract min/max overall gain range
int num_gains = rtlsdr_get_tuner_gains(dev, nullptr);
Expand Down Expand Up @@ -847,4 +878,3 @@ rtlsdr_tuner SoapyRTLSDR::rtlStringToTuner(std::string tunerType)

return deviceTuner;
}

Loading