scpi: add a generic scan API and implement it in usbtmc and serial transport
note that sr_usb_find_serial() is copied from the hameg-hmo driver
This commit is contained in:
parent
17bdda5868
commit
b541f8376d
|
@ -87,6 +87,78 @@ static const struct sr_scpi_dev_inst *scpi_devs[] = {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static GSList *sr_scpi_scan_resource(struct drv_context *drvc,
|
||||||
|
const char *resource, const char *serialcomm,
|
||||||
|
struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi))
|
||||||
|
{
|
||||||
|
struct sr_scpi_dev_inst *scpi;
|
||||||
|
struct sr_dev_inst *sdi;
|
||||||
|
|
||||||
|
if (!(scpi = scpi_dev_inst_new(drvc, resource, serialcomm)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (sr_scpi_open(scpi) != SR_OK) {
|
||||||
|
sr_info("Couldn't open SCPI device.");
|
||||||
|
sr_scpi_free(scpi);
|
||||||
|
return NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((sdi = probe_device(scpi)))
|
||||||
|
return g_slist_append(NULL, sdi);
|
||||||
|
|
||||||
|
sr_scpi_close(scpi);
|
||||||
|
sr_scpi_free(scpi);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
|
||||||
|
struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi))
|
||||||
|
{
|
||||||
|
GSList *resources, *l, *d, *devices = NULL;
|
||||||
|
const char *resource = NULL;
|
||||||
|
const char *serialcomm = NULL;
|
||||||
|
gchar **res;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (l = options; l; l = l->next) {
|
||||||
|
struct sr_config *src = l->data;
|
||||||
|
switch (src->key) {
|
||||||
|
case SR_CONF_CONN:
|
||||||
|
resource = g_variant_get_string(src->data, NULL);
|
||||||
|
break;
|
||||||
|
case SR_CONF_SERIALCOMM:
|
||||||
|
serialcomm = g_variant_get_string(src->data, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(scpi_devs); i++) {
|
||||||
|
if ((resource && strcmp(resource, scpi_devs[i]->prefix))
|
||||||
|
|| !scpi_devs[i]->scan)
|
||||||
|
continue;
|
||||||
|
resources = scpi_devs[i]->scan(drvc);
|
||||||
|
for (l = resources; l; l = l->next) {
|
||||||
|
res = g_strsplit(l->data, ":", 2);
|
||||||
|
if (res[0] && (d = sr_scpi_scan_resource(drvc, res[0],
|
||||||
|
serialcomm ? serialcomm : res[1], probe_device)))
|
||||||
|
devices = g_slist_concat(devices, d);
|
||||||
|
g_strfreev(res);
|
||||||
|
}
|
||||||
|
g_slist_free_full(resources, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!devices && resource)
|
||||||
|
devices = sr_scpi_scan_resource(drvc, resource, serialcomm,
|
||||||
|
probe_device);
|
||||||
|
|
||||||
|
/* Tack a copy of the newly found devices onto the driver list. */
|
||||||
|
if (devices)
|
||||||
|
drvc->instances = g_slist_concat(drvc->instances,
|
||||||
|
g_slist_copy(devices));
|
||||||
|
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
|
SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
|
||||||
const char *resource, const char *serialcomm)
|
const char *resource, const char *serialcomm)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "libsigrok-internal.h"
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LOG_PREFIX "scpi_serial"
|
#define LOG_PREFIX "scpi_serial"
|
||||||
|
@ -35,6 +36,41 @@ struct scpi_serial {
|
||||||
size_t read;
|
size_t read;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
uint16_t vendor_id;
|
||||||
|
uint16_t product_id;
|
||||||
|
const char *serialcomm;
|
||||||
|
} scpi_serial_usb_ids[] = {
|
||||||
|
{ 0x0403, 0xed72, "115200/8n1/flow=1" }, /* Hameg HO720 */
|
||||||
|
{ 0x0403, 0xed73, "115200/8n1/flow=1" }, /* Hameg HO730 */
|
||||||
|
};
|
||||||
|
|
||||||
|
static GSList *scpi_serial_scan(struct drv_context *drvc)
|
||||||
|
{
|
||||||
|
GSList *l, *r, *resources = NULL;
|
||||||
|
gchar *res;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
(void)drvc;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(scpi_serial_usb_ids); i++) {
|
||||||
|
if ((l = sr_serial_find_usb(scpi_serial_usb_ids[i].vendor_id,
|
||||||
|
scpi_serial_usb_ids[i].product_id)) == NULL)
|
||||||
|
continue;
|
||||||
|
for (r = l; r; r = r->next) {
|
||||||
|
if (scpi_serial_usb_ids[i].serialcomm)
|
||||||
|
res = g_strdup_printf("%s:%s", (char *) r->data,
|
||||||
|
scpi_serial_usb_ids[i].serialcomm);
|
||||||
|
else
|
||||||
|
res = g_strdup(r->data);
|
||||||
|
resources = g_slist_append(resources, res);
|
||||||
|
}
|
||||||
|
g_slist_free_full(l, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
static int scpi_serial_dev_inst_new(void *priv, struct drv_context *drvc,
|
static int scpi_serial_dev_inst_new(void *priv, struct drv_context *drvc,
|
||||||
const char *resource, char **params, const char *serialcomm)
|
const char *resource, char **params, const char *serialcomm)
|
||||||
{
|
{
|
||||||
|
@ -190,6 +226,7 @@ SR_PRIV const struct sr_scpi_dev_inst scpi_serial_dev = {
|
||||||
.name = "serial",
|
.name = "serial",
|
||||||
.prefix = "",
|
.prefix = "",
|
||||||
.priv_size = sizeof(struct scpi_serial),
|
.priv_size = sizeof(struct scpi_serial),
|
||||||
|
.scan = scpi_serial_scan,
|
||||||
.dev_inst_new = scpi_serial_dev_inst_new,
|
.dev_inst_new = scpi_serial_dev_inst_new,
|
||||||
.open = scpi_serial_open,
|
.open = scpi_serial_open,
|
||||||
.source_add = scpi_serial_source_add,
|
.source_add = scpi_serial_source_add,
|
||||||
|
|
|
@ -37,6 +37,29 @@ struct usbtmc_scpi {
|
||||||
int response_bytes_read;
|
int response_bytes_read;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static GSList *scpi_usbtmc_scan(struct drv_context *drvc)
|
||||||
|
{
|
||||||
|
GSList *resources = NULL;
|
||||||
|
GDir *dir;
|
||||||
|
const char *dev_name;
|
||||||
|
char *resource;
|
||||||
|
|
||||||
|
(void)drvc;
|
||||||
|
|
||||||
|
if (!(dir = g_dir_open("/sys/class/usbmisc/", 0, NULL)))
|
||||||
|
if (!(dir = g_dir_open("/sys/class/usb/", 0, NULL)))
|
||||||
|
return NULL;
|
||||||
|
while ((dev_name = g_dir_read_name(dir))) {
|
||||||
|
if (strncmp(dev_name, "usbtmc", 6))
|
||||||
|
continue;
|
||||||
|
resource = g_strconcat("/dev/", dev_name, NULL);
|
||||||
|
resources = g_slist_append(resources, resource);
|
||||||
|
}
|
||||||
|
g_dir_close(dir);
|
||||||
|
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
static int scpi_usbtmc_dev_inst_new(void *priv, struct drv_context *drvc,
|
static int scpi_usbtmc_dev_inst_new(void *priv, struct drv_context *drvc,
|
||||||
const char *resource, char **params, const char *serialcomm)
|
const char *resource, char **params, const char *serialcomm)
|
||||||
{
|
{
|
||||||
|
@ -190,6 +213,7 @@ SR_PRIV const struct sr_scpi_dev_inst scpi_usbtmc_dev = {
|
||||||
.name = "USBTMC",
|
.name = "USBTMC",
|
||||||
.prefix = "/dev/usbtmc",
|
.prefix = "/dev/usbtmc",
|
||||||
.priv_size = sizeof(struct usbtmc_scpi),
|
.priv_size = sizeof(struct usbtmc_scpi),
|
||||||
|
.scan = scpi_usbtmc_scan,
|
||||||
.dev_inst_new = scpi_usbtmc_dev_inst_new,
|
.dev_inst_new = scpi_usbtmc_dev_inst_new,
|
||||||
.open = scpi_usbtmc_open,
|
.open = scpi_usbtmc_open,
|
||||||
.source_add = scpi_usbtmc_source_add,
|
.source_add = scpi_usbtmc_source_add,
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
#include <libserialport.h>
|
#include <libserialport.h>
|
||||||
#include "libsigrok.h"
|
#include "libsigrok.h"
|
||||||
#include "libsigrok-internal.h"
|
#include "libsigrok-internal.h"
|
||||||
|
@ -742,3 +743,142 @@ SR_PRIV int serial_source_remove(struct sr_serial_dev_inst *serial)
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find USB serial devices via the USB vendor ID and product ID.
|
||||||
|
*
|
||||||
|
* @param vendor_id Vendor ID of the USB device.
|
||||||
|
* @param product_id Product ID of the USB device.
|
||||||
|
*
|
||||||
|
* @return A GSList of strings containing the path of the serial device or
|
||||||
|
* NULL if no serial device is found. The returned list must be freed
|
||||||
|
* by the caller.
|
||||||
|
*/
|
||||||
|
SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id)
|
||||||
|
{
|
||||||
|
#ifdef __linux__
|
||||||
|
const gchar *usb_dev;
|
||||||
|
const char device_tree[] = "/sys/bus/usb/devices/";
|
||||||
|
GDir *devices_dir, *device_dir;
|
||||||
|
GSList *l = NULL;
|
||||||
|
GSList *tty_devs;
|
||||||
|
GSList *matched_paths;
|
||||||
|
FILE *fd;
|
||||||
|
char tmp[5];
|
||||||
|
gchar *vendor_path, *product_path, *path_copy;
|
||||||
|
gchar *prefix, *subdir_path, *device_path, *tty_path;
|
||||||
|
unsigned long read_vendor_id, read_product_id;
|
||||||
|
const char *file;
|
||||||
|
|
||||||
|
l = NULL;
|
||||||
|
tty_devs = NULL;
|
||||||
|
matched_paths = NULL;
|
||||||
|
|
||||||
|
if (!(devices_dir = g_dir_open(device_tree, 0, NULL)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find potential candidates using the vendor ID and product ID
|
||||||
|
* and store them in matched_paths.
|
||||||
|
*/
|
||||||
|
while ((usb_dev = g_dir_read_name(devices_dir))) {
|
||||||
|
vendor_path = g_strconcat(device_tree,
|
||||||
|
usb_dev, "/idVendor", NULL);
|
||||||
|
product_path = g_strconcat(device_tree,
|
||||||
|
usb_dev, "/idProduct", NULL);
|
||||||
|
|
||||||
|
if (!g_file_test(vendor_path, G_FILE_TEST_EXISTS) ||
|
||||||
|
!g_file_test(product_path, G_FILE_TEST_EXISTS))
|
||||||
|
goto skip_device;
|
||||||
|
|
||||||
|
if ((fd = g_fopen(vendor_path, "r")) == NULL)
|
||||||
|
goto skip_device;
|
||||||
|
|
||||||
|
if (fgets(tmp, sizeof(tmp), fd) == NULL) {
|
||||||
|
fclose(fd);
|
||||||
|
goto skip_device;
|
||||||
|
}
|
||||||
|
read_vendor_id = strtoul(tmp, NULL, 16);
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
if ((fd = g_fopen(product_path, "r")) == NULL)
|
||||||
|
goto skip_device;
|
||||||
|
|
||||||
|
if (fgets(tmp, sizeof(tmp), fd) == NULL) {
|
||||||
|
fclose(fd);
|
||||||
|
goto skip_device;
|
||||||
|
}
|
||||||
|
read_product_id = strtoul(tmp, NULL, 16);
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
if (vendor_id == read_vendor_id &&
|
||||||
|
product_id == read_product_id) {
|
||||||
|
path_copy = g_strdup(usb_dev);
|
||||||
|
matched_paths = g_slist_prepend(matched_paths,
|
||||||
|
path_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_device:
|
||||||
|
g_free(vendor_path);
|
||||||
|
g_free(product_path);
|
||||||
|
}
|
||||||
|
g_dir_close(devices_dir);
|
||||||
|
|
||||||
|
/* For every matched device try to find a ttyUSBX subfolder. */
|
||||||
|
for (l = matched_paths; l; l = l->next) {
|
||||||
|
subdir_path = NULL;
|
||||||
|
|
||||||
|
device_path = g_strconcat(device_tree, l->data, NULL);
|
||||||
|
|
||||||
|
if (!(device_dir = g_dir_open(device_path, 0, NULL))) {
|
||||||
|
g_free(device_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix = g_strconcat(l->data, ":", NULL);
|
||||||
|
|
||||||
|
while ((file = g_dir_read_name(device_dir))) {
|
||||||
|
if (g_str_has_prefix(file, prefix)) {
|
||||||
|
subdir_path = g_strconcat(device_path,
|
||||||
|
"/", file, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_dir_close(device_dir);
|
||||||
|
|
||||||
|
g_free(prefix);
|
||||||
|
g_free(device_path);
|
||||||
|
|
||||||
|
if (subdir_path) {
|
||||||
|
if (!(device_dir = g_dir_open(subdir_path, 0, NULL))) {
|
||||||
|
g_free(subdir_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
g_free(subdir_path);
|
||||||
|
|
||||||
|
while ((file = g_dir_read_name(device_dir))) {
|
||||||
|
if (g_str_has_prefix(file, "ttyUSB")) {
|
||||||
|
tty_path = g_strconcat("/dev/",
|
||||||
|
file, NULL);
|
||||||
|
sr_dbg("Found USB device %04x:%04x attached to %s.",
|
||||||
|
vendor_id, product_id, tty_path);
|
||||||
|
tty_devs = g_slist_prepend(tty_devs,
|
||||||
|
tty_path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_dir_close(device_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_slist_free_full(matched_paths, g_free);
|
||||||
|
|
||||||
|
return tty_devs;
|
||||||
|
#else
|
||||||
|
(void)vendor_id;
|
||||||
|
(void)product_id;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -374,6 +374,7 @@ SR_PRIV int sr_serial_extract_options(GSList *options, const char **serial_devic
|
||||||
SR_PRIV int serial_source_add(struct sr_serial_dev_inst *serial, int events,
|
SR_PRIV int serial_source_add(struct sr_serial_dev_inst *serial, int events,
|
||||||
int timeout, sr_receive_data_callback_t cb, void *cb_data);
|
int timeout, sr_receive_data_callback_t cb, void *cb_data);
|
||||||
SR_PRIV int serial_source_remove(struct sr_serial_dev_inst *serial);
|
SR_PRIV int serial_source_remove(struct sr_serial_dev_inst *serial);
|
||||||
|
SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*--- hardware/common/ezusb.c -----------------------------------------------*/
|
/*--- hardware/common/ezusb.c -----------------------------------------------*/
|
||||||
|
@ -438,6 +439,7 @@ struct sr_scpi_dev_inst {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
int priv_size;
|
int priv_size;
|
||||||
|
GSList *(*scan)(struct drv_context *drvc);
|
||||||
int (*dev_inst_new)(void *priv, struct drv_context *drvc,
|
int (*dev_inst_new)(void *priv, struct drv_context *drvc,
|
||||||
const char *resource, char **params, const char *serialcomm);
|
const char *resource, char **params, const char *serialcomm);
|
||||||
int (*open)(void *priv);
|
int (*open)(void *priv);
|
||||||
|
@ -453,6 +455,8 @@ struct sr_scpi_dev_inst {
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
|
||||||
|
struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi));
|
||||||
SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
|
SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
|
||||||
const char *resource, const char *serialcomm);
|
const char *resource, const char *serialcomm);
|
||||||
SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi);
|
SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi);
|
||||||
|
|
Loading…
Reference in New Issue