Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support specifying VID/PID for scanning + steamline scanning in tools #791

Merged
merged 9 commits into from
Feb 17, 2022
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ include(CheckSymbolExists)
check_symbol_exists(strdup "string.h" HAS_STRDUP)
check_symbol_exists(strndup "string.h" HAS_STRNDUP)
check_symbol_exists(strerror_r "string.h" HAS_STRERROR_R)
check_symbol_exists(strtok_r "string.h" HAS_STRTOK_R)
check_symbol_exists(newlocale "locale.h" HAS_NEWLOCALE)

option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
Expand Down
1 change: 1 addition & 0 deletions iio-config.h.cmakein
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#cmakedefine HAS_PIPE2
#cmakedefine HAS_STRDUP
#cmakedefine HAS_STRNDUP
#cmakedefine HAS_STRTOK_R
#cmakedefine HAS_STRERROR_R
#cmakedefine HAS_NEWLOCALE
#cmakedefine HAS_PTHREAD_SETNAME_NP
Expand Down
4 changes: 3 additions & 1 deletion iio-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ struct iio_context * serial_create_context_from_uri(const char *uri);

int local_context_scan(struct iio_scan_result *scan_result);

int usb_context_scan(struct iio_scan_result *scan_result);
int usb_context_scan(struct iio_scan_result *scan_result, const char *args);

int dnssd_context_scan(struct iio_scan_result *scan_result);

Expand All @@ -260,6 +260,8 @@ void iio_channel_init_finalize(struct iio_channel *chn);
unsigned int find_channel_modifier(const char *s, size_t *len_p);

char *iio_strdup(const char *str);
char *iio_strndup(const char *str, size_t n);
char *iio_strtok_r(char *str, const char *delim, char **saveptr);
size_t iio_strlcpy(char * __restrict dst, const char * __restrict src, size_t dsize);
char * iio_getenv (char * envvar);

Expand Down
19 changes: 14 additions & 5 deletions iio.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,22 @@ enum iio_event_direction {


/** @brief Create a scan context
* @param backend A NULL-terminated string containing the backend(s) to use for
* scanning (example: pre version 0.20 : "local", "ip", or "usb"; post version
* 0.20 can handle multiple, including "local:usb:", "ip:usb:", "local:usb:ip:").
* If NULL, all the available backends are used.
* @param backend A NULL-terminated string containing a comma-separated
* list of the backend(s) to use for scanning.
* @param flags Unused for now. Set to 0.
* @return on success, a pointer to a iio_scan_context structure
* @return On failure, NULL is returned and errno is set appropriately */
* @return On failure, NULL is returned and errno is set appropriately
*
* <b>NOTE:</b> Libiio version 0.20 and above can handle multiple
* strings, for instance "local:usb:", "ip:usb:", "local:usb:ip:", and
* require a colon as the delimiter.
* Libiio version 0.24 and above prefer a comma instead of colon as the
* delimiter, and handle specifying backend-specific information. For
* instance, "local,usb=0456:*" will scan the local backend and limit
* scans on USB to vendor ID 0x0456, and accept all product IDs. The
* "usb=0456:b673" string would limit the scan to the device with this
* particular VID/PID. Both IDs are expected in hexadecimal, no 0x
* prefix needed. */
__api __check_ret struct iio_scan_context * iio_create_scan_context(
const char *backend, unsigned int flags);

Expand Down
2 changes: 1 addition & 1 deletion libiio.rules.cmakein
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SUBSYSTEM=="usb", PROGRAM=="/bin/sh -c '@CMAKE_INSTALL_FULL_BINDIR@/iio_info -S usb | grep %s{idVendor}:%s{idProduct}'", RESULT!="", MODE="666"
SUBSYSTEM=="usb", PROGRAM=="/bin/sh -c '@CMAKE_INSTALL_FULL_BINDIR@/iio_info -S usb=%s{idVendor}:%s{idProduct} | grep %s{idVendor}:%s{idProduct}'", RESULT!="", MODE="666"
7 changes: 5 additions & 2 deletions man/iio_attr.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ Read and Write IIO Context attributes
.B \-D \-\-debug-attr
Read and Write IIO Debug attributes
.TP
.B \-S, \-\-Scan
Scan for available IIO contexts, optional arg of specific backend(s) 'ip', 'usb' or 'ip:usb'. If no argument is given, it checks all that are availble.
.B \-S, \-\-scan
Scan for available IIO contexts, optional arg of specific backend(s) 'ip', 'usb' or 'ip,usb'.
Specific options for USB include Vendor ID, Product ID to limit scanning to specific devices 'usb=0456:b673'.
vid,pid are hexadecimal numbers (no prefix needed), "*" (match any for pid only)
If no argument is given, it checks all that are availble.
.TP
.B \-h, \-\-help
Tells
Expand Down
5 changes: 4 additions & 1 deletion man/iio_info.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ with no address part
.RE
.TP
.B \-S, \-\-scan
Scan for available backends
Scan for available IIO contexts, optional arg of specific backend(s) 'ip', 'usb' or 'ip,usb'.
Specific options for USB include Vendor ID, Product ID to limit scanning to specific devices 'usb=0456:b673'.
vid,pid are hexadecimal numbers (no prefix needed), "*" (match any for pid only)
If no argument is given, it checks all that are availble.
.TP
.B \-a, \-\-auto
Scan for available contexts and if only one is available use it.
Expand Down
7 changes: 6 additions & 1 deletion man/iio_readdev.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,12 @@ Buffer timeout in milliseconds. 0 = no timeout. Default is 0.
.TP
.B \-a, \-\-auto
Scan for available contexts and if only one is available use it.

.TP
.B \-S, \-\-scan
Scan for available IIO contexts, optional arg of specific backend(s) 'ip', 'usb' or 'ip,usb'.
Specific options for USB include Vendor ID, Product ID to limit scanning to specific devices 'usb=0456:b673'.
vid,pid are hexadecimal numbers (no prefix needed), "*" (match any for pid only)
If no argument is given, it checks all that are availble.
.SH RETURN VALUE
If the specified device is not found, a non-zero exit code is returned.

Expand Down
6 changes: 6 additions & 0 deletions man/iio_writedev.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ normally returned from
.IP serial:[port]
.IP local
with no address part
.TP
.B \-S, \-\-scan
Scan for available IIO contexts, optional arg of specific backend(s) 'ip', 'usb' or 'ip,usb'.
Specific options for USB include Vendor ID, Product ID to limit scanning to specific devices 'usb=0456:b673'.
vid,pid are hexadecimal numbers (no prefix needed), "*" (match any for pid only)
If no argument is given, it checks all that are availble.
.RE
.TP
.B \-t \-\-trigger
Expand Down
132 changes: 90 additions & 42 deletions scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@

#include "iio-config.h"
#include "iio-private.h"
#include "sort.h"

#include <errno.h>
#include <stdbool.h>
#include <string.h>

struct iio_scan_context {
bool scan_usb;
bool scan_network;
bool scan_local;
char *backendopts;
};

const char * iio_context_info_get_description(
Expand All @@ -35,52 +34,80 @@ ssize_t iio_scan_context_get_info_list(struct iio_scan_context *ctx,
struct iio_context_info ***info)
{
struct iio_scan_result scan_result = { 0, NULL };

if (WITH_LOCAL_BACKEND && ctx->scan_local) {
int ret = local_context_scan(&scan_result);
if (ret < 0) {
if (scan_result.info)
iio_context_info_list_free(scan_result.info);
return ret;
struct iio_context_info *out;
char *token, *rest=NULL;
size_t i, j = 0;
ssize_t ret;

for (token = iio_strtok_r(ctx->backendopts, ",", &rest);
token; token = iio_strtok_r(NULL, ",", &rest)) {

/* Since tokens are all null terminated, it's safe to use strcmp on them */
if (WITH_LOCAL_BACKEND && !strcmp(token, "local")) {
ret = local_context_scan(&scan_result);
} else if (WITH_USB_BACKEND && (!strcmp(token, "usb") ||
!strncmp(token, "usb=", sizeof("usb=") - 1))) {
token = token[3] == '=' ? token + 4 : NULL;
ret = usb_context_scan(&scan_result, token);
} else if (HAVE_DNS_SD && !strcmp(token, "ip")) {
ret = dnssd_context_scan(&scan_result);
} else {
ret = -ENODEV;
}
if (ret < 0)
goto err_free_scan_result_info;
}

if (WITH_USB_BACKEND && ctx->scan_usb) {
int ret = usb_context_scan(&scan_result);
if (ret < 0) {
if (scan_result.info)
iio_context_info_list_free(scan_result.info);
return ret;
}
}
*info = scan_result.info;

if (HAVE_DNS_SD && ctx->scan_network) {
int ret = dnssd_context_scan(&scan_result);
if (ret < 0) {
if (scan_result.info)
iio_context_info_list_free(scan_result.info);
return ret;
if (scan_result.size > 1) {
qsort(scan_result.info, scan_result.size,
sizeof(struct iio_context_info *),
iio_context_info_compare);

/* there might be duplicates */
for (i = 1; i < scan_result.size; i++) {
/* ipv6 and ipv4 can have the same uri, but have different descriptions,
* so check both if necessary
*/
if ((!strcmp(scan_result.info[i - 1]->uri,
scan_result.info[i]->uri)) &&
(!strcmp(scan_result.info[i - 1]->description,
scan_result.info[i]->description))) {
out = scan_result.info[i - 1];
j++;
free(out->description);
free(out->uri);
out->description = NULL;
out->uri = NULL;
}
}
if (j) {
/* Force all the nulls to the end */
qsort(scan_result.info, scan_result.size,
sizeof(struct iio_context_info *),
iio_context_info_compare);
return (ssize_t) scan_result.size - j;
}
}

*info = scan_result.info;

return (ssize_t) scan_result.size;

err_free_scan_result_info:
if (scan_result.info)
iio_context_info_list_free(scan_result.info);
return ret;
}

void iio_context_info_list_free(struct iio_context_info **list)
{
struct iio_context_info **it;

if (!list)
return;
unsigned int i;

for (it = list; *it; it++) {
struct iio_context_info *info = *it;

free(info->description);
free(info->uri);
free(info);
for (i = 0; list && list[i]; i++) {
free(list[i]->description);
free(list[i]->uri);
free(list[i]);
}

free(list);
Expand Down Expand Up @@ -113,6 +140,8 @@ struct iio_scan_context * iio_create_scan_context(
const char *backend, unsigned int flags)
{
struct iio_scan_context *ctx;
char *ptr, *ptr2;
unsigned int i, len;

/* "flags" must be zero for now */
if (flags != 0) {
Expand All @@ -126,20 +155,39 @@ struct iio_scan_context * iio_create_scan_context(
return NULL;
}

if (!backend || strstr(backend, "local"))
ctx->scan_local = true;

if (!backend || strstr(backend, "usb"))
ctx->scan_usb = true;
ctx->backendopts = iio_strndup(backend ? backend : "local,usb,ip", PATH_MAX);
if (!ctx->backendopts) {
free(ctx);
errno = ENOMEM;
return NULL;
}

if (!backend || strstr(backend, "ip"))
ctx->scan_network = true;
if (backend) {
/* Replace the colon separator with a comma. */
len = strlen(ctx->backendopts);
for (i = 0; i < len; i++)
if (ctx->backendopts[i] == ':')
ctx->backendopts[i] = ',';

/* The only place where a colon is accepted is in the usb arguments:
* usb=vid:pid */
for (ptr = strstr(ctx->backendopts, "usb="); ptr;
ptr = strstr(ptr, "usb=")) {
ptr += sizeof("usb=");
strtoul(ptr, &ptr2, 16);

/* The USB backend will take care of errors */
if (ptr2 != ptr && *ptr2 == ',')
*ptr2 = ':';
}
}

return ctx;
}

void iio_scan_context_destroy(struct iio_scan_context *ctx)
{
free(ctx->backendopts);
free(ctx);
}

Expand Down
17 changes: 17 additions & 0 deletions sort.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,20 @@ int iio_buffer_attr_compare(const void *p1, const void *p2)
return strcmp(tmp1, tmp2);
}

int iio_context_info_compare(const void *p1, const void *p2)
{
int ret;
const struct iio_context_info *tmp1 = *(struct iio_context_info **)p1;
const struct iio_context_info *tmp2 = *(struct iio_context_info **)p2;

if(!tmp1->uri)
return 1;
if (!tmp2->uri)
return 0;

ret = strcmp(tmp1->uri, tmp2->uri);
if (ret)
return ret;

return strcmp(tmp1->description, tmp2->description);
}
1 change: 1 addition & 0 deletions sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ int iio_channel_attr_compare(const void *p1, const void *p2);
int iio_device_compare(const void *p1, const void *p2);
int iio_device_attr_compare(const void *p1, const void *p2);
int iio_buffer_attr_compare(const void *p1, const void *p2);
int iio_context_info_compare(const void *p1, const void *p2);

#endif /* __IIO_QSORT_H__ */
6 changes: 6 additions & 0 deletions tests/iio_adi_xflow_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ int main(int argc, char **argv)
char unit;
int ret;
struct option *opts;
bool do_scan = false;

argw = dup_argv(MY_NAME, argc, argv);

Expand All @@ -188,6 +189,8 @@ int main(int argc, char **argv)
case 'T':
break;
case 'S':
do_scan = true;
/* FALLTHROUGH */
case 'a':
if (!optarg && argc > optind && argv[optind] != NULL
&& argv[optind][0] != '-')
Expand Down Expand Up @@ -215,6 +218,9 @@ int main(int argc, char **argv)
}
free(opts);

if (do_scan)
return EXIT_SUCCESS;

if (optind + 1 != argc) {
fprintf(stderr, "Incorrect number of arguments.\n\n");
usage(MY_NAME, options, options_descriptions);
Expand Down
Loading