]> sigrok.org Git - libsigrok.git/commitdiff
scpi: add a generic scan API and implement it in usbtmc and serial transport
authorAurelien Jacobs <redacted>
Sun, 2 Feb 2014 20:47:45 +0000 (21:47 +0100)
committerUwe Hermann <redacted>
Fri, 7 Feb 2014 17:53:04 +0000 (18:53 +0100)
note that sr_usb_find_serial() is copied from the hameg-hmo driver

hardware/common/scpi.c
hardware/common/scpi_serial.c
hardware/common/scpi_usbtmc.c
hardware/common/serial.c
libsigrok-internal.h

index 2307a8b5f377acdf03f67d5be4cc9650de3ffde3..618ff058885ddb42b7b3661cbd4b6763f6e0e009 100644 (file)
@@ -87,6 +87,78 @@ static const struct sr_scpi_dev_inst *scpi_devs[] = {
 #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,
                const char *resource, const char *serialcomm)
 {
index 6e73c8944df39b0a84144b03d98f3c761dc87ff6..e0936c01ec163eb6748c1a650e17dbcd50fd4195 100644 (file)
@@ -22,6 +22,7 @@
 #include "libsigrok-internal.h"
 
 #include <glib.h>
+#include <stdlib.h>
 #include <string.h>
 
 #define LOG_PREFIX "scpi_serial"
@@ -35,6 +36,41 @@ struct scpi_serial {
        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,
                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",
        .prefix        = "",
        .priv_size     = sizeof(struct scpi_serial),
+       .scan          = scpi_serial_scan,
        .dev_inst_new  = scpi_serial_dev_inst_new,
        .open          = scpi_serial_open,
        .source_add    = scpi_serial_source_add,
index 6cd79641b90b9ca71dd3447a9cc856b0baf18bf7..1ffc34ae9392c8826161e21e669eaef232daafeb 100644 (file)
@@ -37,6 +37,29 @@ struct usbtmc_scpi {
        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,
                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",
        .prefix        = "/dev/usbtmc",
        .priv_size     = sizeof(struct usbtmc_scpi),
+       .scan          = scpi_usbtmc_scan,
        .dev_inst_new  = scpi_usbtmc_dev_inst_new,
        .open          = scpi_usbtmc_open,
        .source_add    = scpi_usbtmc_source_add,
index a267d6fb88367fa246c3c739a697b218e110a0dc..32a6d23c087f61ca046f607811a38465ce21ce1e 100644 (file)
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <glib.h>
+#include <glib/gstdio.h>
 #include <libserialport.h>
 #include "libsigrok.h"
 #include "libsigrok-internal.h"
@@ -742,3 +743,142 @@ SR_PRIV int serial_source_remove(struct sr_serial_dev_inst *serial)
 
        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
+}
index 951d91d9542eb2c69afccbd6c7b5547ef03d5136..90e40342518d3da1c41dddf2338333d74cb1ced3 100644 (file)
@@ -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,
                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 GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id);
 #endif
 
 /*--- hardware/common/ezusb.c -----------------------------------------------*/
@@ -438,6 +439,7 @@ struct sr_scpi_dev_inst {
        const char *name;
        const char *prefix;
        int priv_size;
+       GSList *(*scan)(struct drv_context *drvc);
        int (*dev_inst_new)(void *priv, struct drv_context *drvc,
                const char *resource, char **params, const char *serialcomm);
        int (*open)(void *priv);
@@ -453,6 +455,8 @@ struct sr_scpi_dev_inst {
        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,
                const char *resource, const char *serialcomm);
 SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi);