]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/serial-lcr/api.c
serial: extend stream detect for variable length packet checkers
[libsigrok.git] / src / hardware / serial-lcr / api.c
index 0919ae8891f71e580b7b74287adcc4f50edc4311..7f3fc5362ae1b980991857be4b88d7d66d2be0ad 100644 (file)
@@ -38,7 +38,7 @@ static const uint32_t drvopts[] = {
 
 static const uint32_t devopts[] = {
        SR_CONF_CONTINUOUS,
-       SR_CONF_LIMIT_FRAMES | SR_CONF_SET,
+       SR_CONF_LIMIT_FRAMES | SR_CONF_GET | SR_CONF_SET,
        SR_CONF_LIMIT_MSEC | SR_CONF_SET,
        SR_CONF_OUTPUT_FREQUENCY | SR_CONF_GET | SR_CONF_LIST,
        SR_CONF_EQUIV_CIRCUIT_MODEL | SR_CONF_GET | SR_CONF_LIST,
@@ -85,46 +85,16 @@ static gboolean scan_packet_check_func(const uint8_t *buf)
        return TRUE;
 }
 
-static GSList *scan(struct sr_dev_driver *di, GSList *options)
+static int scan_lcr_port(const struct lcr_info *lcr,
+       const char *conn, struct sr_serial_dev_inst *serial)
 {
-       struct lcr_info *lcr;
-       struct sr_config *src;
-       GSList *l, *devices;
-       const char *conn, *serialcomm;
-       struct sr_serial_dev_inst *serial;
+       size_t len;
        uint8_t buf[128];
-       size_t len, dropped;
        int ret;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       size_t ch_idx;
-       const char **ch_fmts;
-       const char *fmt;
-       char ch_name[8];
-
-       lcr = (struct lcr_info *)di;
-
-       /* Get serial port name and communication parameters. */
-       conn = NULL;
-       serialcomm = lcr->comm;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
+       size_t dropped;
 
-       /* Open the serial port. */
-       serial = sr_serial_dev_inst_new(conn, serialcomm);
        if (serial_open(serial, SERIAL_RDWR) != SR_OK)
-               return NULL;
+               return SR_ERR_IO;
        sr_info("Probing serial port %s.", conn);
 
        /*
@@ -135,20 +105,18 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
         * send data periodically. So we check if the packets match the
         * probed device's expected format.
         */
-       devices = NULL;
-       serial_flush(serial);
        if (lcr->packet_request) {
                ret = lcr->packet_request(serial);
                if (ret < 0) {
                        sr_err("Failed to request packet: %d.", ret);
-                       goto scan_cleanup;
+                       goto scan_port_cleanup;
                }
        }
        len = sizeof(buf);
        ret = serial_stream_detect(serial, buf, &len,
-               lcr->packet_size, lcr->packet_valid, 3000);
+               lcr->packet_size, lcr->packet_valid, NULL, NULL, 3000);
        if (ret != SR_OK)
-               goto scan_cleanup;
+               goto scan_port_cleanup;
 
        /*
         * If the packets were found to match after more than two packets
@@ -162,6 +130,25 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
 
        /* Create a device instance for the found device. */
        sr_info("Found %s %s device on port %s.", lcr->vendor, lcr->model, conn);
+
+scan_port_cleanup:
+       /* Keep serial port open if probe succeeded. */
+       if (ret != SR_OK)
+               serial_close(serial);
+
+       return ret;
+}
+
+static struct sr_dev_inst *create_lcr_sdi(struct lcr_info *lcr,
+       struct sr_serial_dev_inst *serial)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       size_t ch_idx;
+       const char **ch_fmts;
+       const char *fmt;
+       char ch_name[8];
+
        sdi = g_malloc0(sizeof(*sdi));
        sdi->status = SR_ST_INACTIVE;
        sdi->vendor = g_strdup(lcr->vendor);
@@ -178,7 +165,25 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
                snprintf(ch_name, sizeof(ch_name), fmt, ch_idx + 1);
                sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, ch_name);
        }
-       devices = g_slist_append(devices, sdi);
+
+       return sdi;
+}
+
+static int read_lcr_port(struct sr_dev_inst *sdi,
+       const struct lcr_info *lcr, struct sr_serial_dev_inst *serial)
+{
+       size_t len;
+       uint8_t buf[128];
+       int ret;
+
+       serial_flush(serial);
+       if (lcr->packet_request) {
+               ret = lcr->packet_request(serial);
+               if (ret < 0) {
+                       sr_err("Failed to request packet: %d.", ret);
+                       return ret;
+               }
+       }
 
        /*
         * Receive a few more packets (and process them!) to have the
@@ -193,11 +198,57 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
        len = sizeof(buf);
        scan_packet_check_setup(sdi);
        ret = serial_stream_detect(serial, buf, &len,
-               lcr->packet_size, scan_packet_check_func, 1000);
+               lcr->packet_size, scan_packet_check_func, NULL, NULL, 1500);
        scan_packet_check_setup(NULL);
 
-scan_cleanup:
-       serial_close(serial);
+       return ret;
+}
+
+static GSList *scan(struct sr_dev_driver *di, GSList *options)
+{
+       struct lcr_info *lcr;
+       struct sr_config *src;
+       GSList *l, *devices;
+       const char *conn, *serialcomm;
+       struct sr_serial_dev_inst *serial;
+       int ret;
+       struct sr_dev_inst *sdi;
+
+       lcr = (struct lcr_info *)di;
+
+       /* Get serial port name and communication parameters. */
+       conn = NULL;
+       serialcomm = lcr->comm;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+
+       devices = NULL;
+       /* TODO Handle ambiguous conn= specs, see serial-dmm. */
+
+       /* Open the serial port, check data packets. */
+       serial = sr_serial_dev_inst_new(conn, serialcomm);
+       ret = scan_lcr_port(lcr, conn, serial);
+       if (ret != SR_OK) {
+               /* Probe failed, release 'serial'. */
+               sr_serial_dev_inst_free(serial);
+       } else {
+               /* Create and return device instance, keep 'serial' alive. */
+               sdi = create_lcr_sdi(lcr, serial);
+               devices = g_slist_append(devices, sdi);
+               (void)read_lcr_port(sdi, lcr, serial);
+               serial_close(serial);
+       }
 
        return std_scan_complete(di, devices);
 }
@@ -347,3 +398,36 @@ SR_REGISTER_DEV_DRIVER_LIST(lcr_es51919_drivers,
        LCR_ES51919("peaktech-2170", "PeakTech", "2170"),
        LCR_ES51919("uni-t-ut612", "UNI-T", "UT612"),
 );
+
+#define LCR_VC4080(id, vendor, model) \
+       &((struct lcr_info) { \
+               { \
+                       .name = id, \
+                       .longname = vendor " " model, \
+                       .api_version = 1, \
+                       .init = std_init, \
+                       .cleanup = std_cleanup, \
+                       .scan = scan, \
+                       .dev_list = std_dev_list, \
+                       .dev_clear = std_dev_clear, \
+                       .config_get = config_get, \
+                       .config_set = config_set, \
+                       .config_list = config_list, \
+                       .dev_open = std_serial_dev_open, \
+                       .dev_close = std_serial_dev_close, \
+                       .dev_acquisition_start = dev_acquisition_start, \
+                       .dev_acquisition_stop = std_serial_dev_acquisition_stop, \
+                       .context = NULL, \
+               }, \
+               vendor, model, \
+               VC4080_CHANNEL_COUNT, vc4080_channel_formats, \
+               VC4080_COMM_PARAM, VC4080_PACKET_SIZE, \
+               500, vc4080_packet_request, \
+               vc4080_packet_valid, vc4080_packet_parse, \
+               NULL, NULL, vc4080_config_list, \
+       }).di
+
+SR_REGISTER_DEV_DRIVER_LIST(lcr_vc4080_drivers,
+       LCR_VC4080("peaktech-2165", "PeakTech", "2165"),
+       LCR_VC4080("voltcraft-4080", "Voltcraft", "4080"),
+);