I'm using a Raspberry with two similar devices but different antennas.
Specifying the device via index didn't work, because the enumeration of
devices changed from time to time. Therefore I implemented functions to
give a USB path instead. This path looks the same as the Linux kernel
uses (eg. "4-1.2") and contains the USB bus and port numbers.
I'll hope you'll find my patch acceptable.
Best Regards,
Alex
Add functions to query devices via path, and path from a device.
The path is formatted similar to Linux USB device names (bus number,
hyphen, ports separated by dots, eg. "4-1.2").
---
include/rtl-sdr.h | 25 +++++++
src/convenience/convenience.c | 10 +++
src/librtlsdr.c | 121 ++++++++++++++++++++++++++++++++++
3 files changed, 156 insertions(+)
diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h
index d64701e..e6ce33a 100644
--- a/include/rtl-sdr.h
+++ b/include/rtl-sdr.h
@@ -49,6 +49,31 @@ RTLSDR_API int rtlsdr_get_device_usb_strings(uint32_t index,
char *product,
char *serial);
+/*!
+ * Get device index by USB path string.
+ *
+ * The path string has the format "bus-port.port..."
+ * (i.e. the bus number, followed by a hyphen, then
+ * followed by the port numbers separated by dots).
+ *
+ * \param path path string of the device
+ * \return device index of the device with the given path
+ * \return -1 if no matching device was found.
+ */
+RTLSDR_API int rtlsdr_get_index_by_path(const char *path);
+
+/*!
+ * Get the USB path.
+ *
+ * NOTE: The buffer should provide space for at least 32 bytes.
+ *
+ * \param index the device index
+ * \param buf buffer where the path will be written
+ * \param len size of the buffer
+ * \return 0 on success
+ */
+RTLSDR_API int rtlsdr_get_device_path(uint32_t index, char *buf, size_t len);
+
/*!
* Get device index by USB serial string descriptor.
*
diff --git a/src/convenience/convenience.c b/src/convenience/convenience.c
index 00cc2cc..55f82e2 100644
--- a/src/convenience/convenience.c
+++ b/src/convenience/convenience.c
@@ -268,6 +268,16 @@ int verbose_device_search(char *s)
device, rtlsdr_get_device_name((uint32_t)device));
return device;
}
+ /* does string match a path */
+ if (s2[0] == '-') {
+ i = rtlsdr_get_index_by_path(s);
+ if (i >= 0) {
+ device = i;
+ fprintf(stderr, "Using device %d: %s\n",
+ device, rtlsdr_get_device_name((uint32_t)device));
+ return device;
+ }
+ }
/* does string exact match a serial */
for (i = 0; i < device_count; i++) {
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index 0146298..e3f03d7 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -1414,6 +1414,127 @@ int rtlsdr_get_device_usb_strings(uint32_t index, char *manufact,
return r;
}
+static void get_device_path(libusb_device *dev, char *buf, size_t len)
+{
+ uint8_t port_numbers[16];
+ int port_entries;
+ int i, count;
+
+ count = snprintf(buf, len, "%d-", (int)libusb_get_bus_number(dev));
+ if (count < 0) {
+ buf[0] = 0;
+ return;
+ }
+ else if ((size_t)count >= len) {
+ buf[len-1] = 0;
+ return;
+ }
+
+ len -= count;
+ buf += count;
+
+ port_entries = libusb_get_port_numbers(dev, port_numbers, sizeof(port_numbers)/sizeof(port_numbers[0]));
+ if (port_entries < 0)
+ return;
+
+ for (i = 0; i < port_entries; i++) {
+ count = snprintf(buf, len, i ? ".%d" : "%d", (int) port_numbers[i]);
+
+ if (count < 0) {
+ buf[0] = 0;
+ break;
+ }
+ else if ((size_t)count >= len) {
+ buf[len-1] = 0;
+ break;
+ }
+
+ len -= count;
+ buf += count;
+ }
+
+ if (!port_entries && len > 1) {
+ buf[0] = '0';
+ buf[1] = 0;
+ }
+}
+
+int rtlsdr_get_index_by_path(const char *path)
+{
+ libusb_context *ctx;
+ libusb_device **list;
+ struct libusb_device_descriptor dd;
+ ssize_t cnt;
+ int i,r,pos;
+
+ r = libusb_init(&ctx);
+
+ if(r < 0)
+ return -1;
+
+ cnt = libusb_get_device_list(ctx, &list);
+
+ pos = 0;
+ for (i = 0; i < cnt; i++) {
+ libusb_get_device_descriptor(list[i], &dd);
+
+ if (find_known_device(dd.idVendor, dd.idProduct)) {
+ char buf[64];
+ get_device_path(list[i], buf, sizeof(buf));
+
+ if (!strncmp(path, buf, sizeof(buf))) {
+ libusb_free_device_list(list, 1);
+ libusb_exit(ctx);
+
+ return pos;
+ }
+
+ pos++;
+ }
+ }
+
+ libusb_free_device_list(list, 1);
+ libusb_exit(ctx);
+
+ return -1;
+}
+
+int rtlsdr_get_device_path(uint32_t index, char *buf, size_t len)
+{
+ libusb_context *ctx;
+ libusb_device **list;
+ struct libusb_device_descriptor dd;
+ int i,r;
+ uint32_t device_count = 0;
+ ssize_t cnt;
+
+ r = libusb_init(&ctx);
+ if(r < 0)
+ return r;
+
+ cnt = libusb_get_device_list(ctx, &list);
+
+ r = LIBUSB_ERROR_NO_DEVICE;
+ for (i = 0; i < cnt; i++) {
+ libusb_get_device_descriptor(list[i], &dd);
+
+ if (find_known_device(dd.idVendor, dd.idProduct)) {
+ device_count++;
+
+ if (index == device_count - 1) {
+ get_device_path(list[i], buf, len);
+ r = 0;
+ break;
+ }
+ }
+ }
+
+ libusb_free_device_list(list, 1);
+ libusb_exit(ctx);
+
+ return r;
+}
+
int rtlsdr_get_index_by_serial(const char *serial)
{
int i, cnt, r;
--
2.20.1