forked from pgreenland/SoapyPlutoSDR
-
Notifications
You must be signed in to change notification settings - Fork 0
/
PlutoSDR_Registration.cpp
154 lines (130 loc) · 4.96 KB
/
PlutoSDR_Registration.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include "SoapyPlutoSDR.hpp"
#include <SoapySDR/Registry.hpp>
#include <sstream>
#include <chrono>
#include <thread>
#ifdef HAS_LIBUSB1
#include <libusb.h>
#endif
static std::vector<SoapySDR::Kwargs> results;
static std::vector<SoapySDR::Kwargs> find_PlutoSDR(const SoapySDR::Kwargs &args) {
if (!results.empty())
return results;
ssize_t ret = 0;
iio_context *ctx = nullptr;
iio_scan_context *scan_ctx;
iio_context_info **info;
SoapySDR::Kwargs options;
// Backends can error, scan each one individually
// The filtered "usb" backend is available starting from Libiio 0.24
std::vector<std::string> backends = {"local", "usb=0456:b673", "ip"};
for (std::vector<std::string>::iterator it = backends.begin(); it != backends.end(); it++) {
if (*it == "usb=0456:b673") {
#ifdef HAS_LIBUSB1
// Abort early if no known ADALM-Pluto USB VID:PID (0456:b673) is found,
// that way we won't block USB access for other drivers' enumeration on Libiio before 0.24.
libusb_context *usb_ctx = nullptr;
int r = libusb_init(&usb_ctx);
if (r < 0) {
SoapySDR_logf(SOAPY_SDR_WARNING, "libusb init error (%d)\n", r);
}
else {
// This is what libusb_open_device_with_vid_pid(usb_ctx, 0x0456, 0xb673) does,
// but without actually opening a device.
struct libusb_device **devs;
// this is cached in libusb, we won't block USB access for other drivers
r = libusb_get_device_list(usb_ctx, &devs);
if (r < 0) {
SoapySDR_logf(SOAPY_SDR_WARNING, "libusb get device list error (%d)\n", r);
continue; // iio scan context will most likely fail too?
}
bool found = false;
struct libusb_device *dev;
size_t i = 0;
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
// this is cached in libusb, we won't block USB access for other drivers
r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
break;
}
if (desc.idVendor == 0x0456 && desc.idProduct == 0xb673) {
found = true;
break;
}
}
libusb_free_device_list(devs, 1);
if (found) {
SoapySDR_logf(SOAPY_SDR_DEBUG, "ADALM-Pluto VID:PID found");
}
else {
SoapySDR_logf(SOAPY_SDR_DEBUG, "No ADALM-Pluto VID:PID found");
continue;
}
}
#endif
// Defer to other drivers, prevent a race condition on USB enumeration with Libiio before 0.24,
// the value of 500ms has not been confirmed and might be 50ms to 1s possibly.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
scan_ctx = iio_create_scan_context(it->c_str(), 0);
if (scan_ctx == nullptr) {
SoapySDR_logf(SOAPY_SDR_WARNING, "Unable to setup %s scan\n", it->c_str());
continue;
}
info = nullptr;
ret = iio_scan_context_get_info_list(scan_ctx, &info);
if (ret < 0) {
SoapySDR_logf(SOAPY_SDR_WARNING, "Unable to scan %s: %li\n", it->c_str(), (long)ret);
iio_context_info_list_free(info);
iio_scan_context_destroy(scan_ctx);
continue;
}
options["device"] = "PlutoSDR";
if (ret == 0) {
iio_context_info_list_free(info);
iio_scan_context_destroy(scan_ctx);
//no devices discovered, the user must specify a hostname
if (args.count("hostname") == 0) continue;
//try to connect at the specified hostname
ctx = iio_create_network_context(args.at("hostname").c_str());
if (ctx == nullptr) continue; //failed to connect
options["hostname"] = args.at("hostname");
std::ostringstream label_str;
label_str << options["device"] << " #0 " << options["hostname"];
options["label"] = label_str.str();
results.push_back(options);
if (ctx != nullptr) iio_context_destroy(ctx);
} else {
for (int i = 0; i < ret; i++) {
ctx = iio_create_context_from_uri(iio_context_info_get_uri(info[i]));
if (ctx != nullptr) {
options["uri"] = std::string(iio_context_info_get_uri(info[i]));
// check if discovered libiio context can be a PlutoSDR (and not some other sensor),
// it must contain "ad9361-phy", "cf-ad9361-lpc" and "cf-ad9361-dds-core-lpc" devices
iio_device *dev = iio_context_find_device(ctx, "ad9361-phy");
iio_device *rx_dev = iio_context_find_device(ctx, "cf-ad9361-lpc");
iio_device *tx_dev = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc");
if (dev != nullptr && rx_dev != nullptr && tx_dev != nullptr) {
// if uri is specified in kwargs, discovered uri must match
if (args.count("uri") == 0 || options["uri"] == args.at("uri")) {
std::ostringstream label_str;
label_str << options["device"] << " #" << i << " " << options["uri"];
options["label"] = label_str.str();
results.push_back(options);
}
}
if (ctx != nullptr) iio_context_destroy(ctx);
}
}
iio_context_info_list_free(info);
iio_scan_context_destroy(scan_ctx);
}
}
return results;
}
static SoapySDR::Device *make_PlutoSDR(const SoapySDR::Kwargs &args)
{
return new SoapyPlutoSDR(args);
}
static SoapySDR::Registry register_plutosdr("plutosdr", &find_PlutoSDR, &make_PlutoSDR, SOAPY_SDR_ABI_VERSION);