]> sigrok.org Git - libsigrok.git/commitdiff
serial-lcr: move device driver code from src/lcr/ to src/hardware/
authorGerhard Sittig <redacted>
Wed, 1 May 2019 20:01:48 +0000 (22:01 +0200)
committerGerhard Sittig <redacted>
Wed, 12 Jun 2019 20:01:52 +0000 (22:01 +0200)
Keep the ES51919 chip support in the src/lcr/ directory, and move device
driver specific code to the src/hardware/serial-lcr/ directory. Implement
the same driver layout for LCR meters as is used for DMM devices.

This also addresses a few issues in the serial-lcr driver: Unbreak --get
and --show, do process a few LCR packets after probing the device, to
gather current parameter values. Keep sending meta packets when these
parameters change during acquisition, like the previous implementation
did. Use common code for frame/time limits.

Note that although LCR meters usually operate with AC to classify L/C/R
components, one of the officially supported modes is DC resistance.
Which means that an output frequency of 0 is not just a fallback when
packet parsing fails, it's also a regular value of the freq parameter.
List all supported frequencies including DC in strict numerical order.

Although all currently supported devices use the same ES51919 chip, the
implementation is prepared to support other devices which use different
LCR meter chips as well. The list of known equivalent circuit models and
output frequencies is kept in src/lcr/ chip support. It's assumed that
one LCR packet communicates the data for all channels/displays similar
to the serial-dmm driver implementation.

Makefile.am
src/hardware/serial-lcr/api.c
src/hardware/serial-lcr/protocol.c [new file with mode: 0644]
src/hardware/serial-lcr/protocol.h [new file with mode: 0644]
src/lcr/es51919.c
src/libsigrok-internal.h

index e871b9f0fe32e60ea602870204be0d63dde0d887..96542f62cdec5fce88a8e9ed9cc7723b6f6af171 100644 (file)
@@ -546,6 +546,8 @@ src_libdrivers_la_SOURCES += \
 endif
 if HW_SERIAL_LCR
 src_libdrivers_la_SOURCES += \
+       src/hardware/serial-lcr/protocol.h \
+       src/hardware/serial-lcr/protocol.c \
        src/hardware/serial-lcr/api.c
 endif
 if HW_SIGLENT_SDS
index bbec3809df006722b06ca98c81ea94582445fcbc..002fb5bf3293db1142e206fbdee6aa366d745d87 100644 (file)
@@ -2,6 +2,7 @@
  * This file is part of the libsigrok project.
  *
  * Copyright (C) 2014 Janne Huttunen <jahuttun@gmail.com>
+ * Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 
 #include <config.h>
-#include <stdint.h>
-#include <string.h>
-#include <math.h>
 #include <glib.h>
 #include <libsigrok/libsigrok.h>
 #include "libsigrok-internal.h"
+#include <math.h>
+#include "protocol.h"
+#include <stdint.h>
+#include <string.h>
 
-#define LOG_PREFIX "serial-lcr-es51919"
+static const uint32_t scanopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const uint32_t drvopts[] = {
+       SR_CONF_LCRMETER,
+};
 
-struct lcr_es51919_info {
-       struct sr_dev_driver di;
-       const char *vendor;
-       const char *model;
+static const uint32_t devopts[] = {
+       SR_CONF_CONTINUOUS,
+       SR_CONF_LIMIT_FRAMES | 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,
 };
 
-static int dev_clear(const struct sr_dev_driver *di)
+static struct sr_dev_inst *scan_packet_check_devinst;
+
+static void scan_packet_check_setup(struct sr_dev_inst *sdi)
+{
+       scan_packet_check_devinst = sdi;
+}
+
+static gboolean scan_packet_check_func(const uint8_t *buf)
 {
-       return std_dev_clear_with_callback(di, es51919_serial_clean);
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       const struct lcr_info *lcr;
+       struct lcr_parse_info *info;
+
+       /* Get a reference to the LCR model that is getting checked. */
+       sdi = scan_packet_check_devinst;
+       if (!sdi)
+               return FALSE;
+       devc = sdi->priv;
+       if (!devc)
+               return FALSE;
+       lcr = devc->lcr_info;
+       if (!lcr)
+               return FALSE;
+
+       /* Synchronize to the stream of LCR packets. */
+       if (!lcr->packet_valid(buf))
+               return FALSE;
+
+       /* Have LCR packets _processed_, gather current configuration. */
+       info = &devc->parse_info;
+       memset(info, 0, sizeof(*info));
+       if (lcr->packet_parse(buf, NULL, NULL, info) == SR_OK) {
+                devc->output_freq = info->output_freq;
+                if (info->circuit_model)
+                        devc->circuit_model = info->circuit_model;
+        }
+
+       return TRUE;
 }
 
 static GSList *scan(struct sr_dev_driver *di, GSList *options)
 {
-       struct lcr_es51919_info *lcr;
+       struct lcr_info *lcr;
+       struct sr_config *src;
+       GSList *l, *devices;
+       const char *conn, *serialcomm;
+       struct sr_serial_dev_inst *serial;
+       uint8_t buf[128];
+       size_t len, dropped;
+       int ret;
        struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       size_t ch_idx;
+       char ch_name[8];
 
-       lcr = (struct lcr_es51919_info *)di;
+       lcr = (struct lcr_info *)di;
 
-       if (!(sdi = es51919_serial_scan(options, lcr->vendor, lcr->model)))
+       /* 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;
 
-       return std_scan_complete(di, g_slist_append(NULL, sdi));
+       /* Open the serial port. */
+       serial = sr_serial_dev_inst_new(conn, serialcomm);
+       if (serial_open(serial, SERIAL_RDWR) != SR_OK)
+               return NULL;
+       sr_info("Probing serial port %s.", conn);
+
+       /*
+        * See if we can detect a device of specified type.
+        *
+        * No supported device provides a means to "identify" yet. No
+        * supported device requires "packet request" yet. They all just
+        * send data periodically. So we check if the packets match the
+        * probed device's expected format.
+        */
+       serial_flush(serial);
+       devices = NULL;
+       len = sizeof(buf);
+       ret = serial_stream_detect(serial, buf, &len,
+               lcr->packet_size, lcr->packet_valid, 3000);
+       if (ret != SR_OK)
+               goto scan_cleanup;
+
+       /*
+        * If the packets were found to match after more than two packets
+        * got dropped, something is wrong. This is worth warning about,
+        * but isn't fatal. The dropped bytes might be due to nonstandard
+        * cables that ship with some devices.
+        */
+       dropped = len - lcr->packet_size;
+       if (dropped > 2 * lcr->packet_size)
+               sr_warn("Had to drop unexpected amounts of data.");
+
+       /* Create a device instance for the found device. */
+       sr_info("Found %s %s device on port %s.", lcr->vendor, lcr->model, conn);
+       sdi = g_malloc0(sizeof(*sdi));
+       sdi->status = SR_ST_INACTIVE;
+       sdi->vendor = g_strdup(lcr->vendor);
+       sdi->model = g_strdup(lcr->model);
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+       devc = g_malloc0(sizeof(*devc));
+       sdi->priv = devc;
+       devc->lcr_info = lcr;
+       sr_sw_limits_init(&devc->limits);
+       for (ch_idx = 0; ch_idx < lcr->channel_count; ch_idx++) {
+               snprintf(ch_name, sizeof(ch_name), "P%zu", ch_idx + 1);
+               sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, ch_name);
+       }
+       devices = g_slist_append(devices, sdi);
+
+       /*
+        * Receive a few more packets (and process them!) to have the
+        * current output frequency and circuit model parameter values
+        * detected. The above "stream detect" phase only synchronized
+        * to the packets by checking their validity, but it cannot
+        * provide details. This phase here runs a modified "checker"
+        * routine which also extracts details from LCR packets after
+        * the device got detected and parameter storage was prepared.
+        */
+       sr_info("Retrieving current acquisition parameters.");
+       len = sizeof(buf);
+       scan_packet_check_setup(sdi);
+       ret = serial_stream_detect(serial, buf, &len,
+               lcr->packet_size, scan_packet_check_func, 1000);
+       scan_packet_check_setup(NULL);
+
+scan_cleanup:
+       serial_close(serial);
+
+       return std_scan_complete(di, devices);
+}
+
+static int config_get(uint32_t key, GVariant **data,
+       const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       const struct lcr_info *lcr;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_LIMIT_FRAMES:
+       case SR_CONF_LIMIT_MSEC:
+               return sr_sw_limits_config_get(&devc->limits, key, data);
+       case SR_CONF_OUTPUT_FREQUENCY:
+               *data = g_variant_new_double(devc->output_freq);
+               return SR_OK;
+       case SR_CONF_EQUIV_CIRCUIT_MODEL:
+               if (!devc->circuit_model)
+                       return SR_ERR_NA;
+               *data = g_variant_new_string(devc->circuit_model);
+               return SR_OK;
+       default:
+               lcr = devc->lcr_info;
+               if (!lcr)
+                       return SR_ERR_NA;
+               if (!lcr->config_get)
+                       return SR_ERR_NA;
+               return lcr->config_get(key, data, sdi, cg);
+       }
+       /* UNREACH */
+}
+
+static int config_set(uint32_t key, GVariant *data,
+       const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       const struct lcr_info *lcr;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_LIMIT_FRAMES:
+       case SR_CONF_LIMIT_MSEC:
+               return sr_sw_limits_config_set(&devc->limits, key, data);
+       default:
+               lcr = devc->lcr_info;
+               if (!lcr)
+                       return SR_ERR_NA;
+               if (!lcr->config_set)
+                       return SR_ERR_NA;
+               return lcr->config_set(key, data, sdi, cg);
+       }
+       /* UNREACH */
+}
+
+static int config_list(uint32_t key, GVariant **data,
+       const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       const struct lcr_info *lcr;
+
+       switch (key) {
+       case SR_CONF_SCAN_OPTIONS:
+       case SR_CONF_DEVICE_OPTIONS:
+               return STD_CONFIG_LIST(key, data, sdi, cg,
+                       scanopts, drvopts, devopts);
+       default:
+               break;
+       }
+
+       if (!sdi)
+               return SR_ERR_ARG;
+       devc = sdi->priv;
+       switch (key) {
+       default:
+               lcr = devc->lcr_info;
+               if (!lcr || !lcr->config_list)
+                       return SR_ERR_NA;
+               return lcr->config_list(key, data, sdi, cg);
+       }
+       /* UNREACH */
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       devc = sdi->priv;
+
+       /*
+        * Clear values that were gathered during scan or in a previous
+        * acquisition, so that this acquisition's data feed immediately
+        * starts with meta packets before first measurement values, and
+        * also communicates subsequent parameter changes.
+        */
+       devc->output_freq = 0;
+       devc->circuit_model = NULL;
+
+       sr_sw_limits_acquisition_start(&devc->limits);
+       std_session_send_df_header(sdi);
+
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 50,
+               lcr_receive_data, (void *)sdi);
+
+       return SR_OK;
 }
 
 #define LCR_ES51919(id, vendor, model) \
-       &((struct lcr_es51919_info) { \
+       &((struct lcr_info) { \
                { \
                        .name = id, \
                        .longname = vendor " " model, \
@@ -61,17 +313,20 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
                        .cleanup = std_cleanup, \
                        .scan = scan, \
                        .dev_list = std_dev_list, \
-                       .dev_clear = dev_clear, \
-                       .config_get = es51919_serial_config_get, \
-                       .config_set = es51919_serial_config_set, \
-                       .config_list = es51919_serial_config_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 = es51919_serial_acquisition_start, \
+                       .dev_acquisition_start = dev_acquisition_start, \
                        .dev_acquisition_stop = std_serial_dev_acquisition_stop, \
                        .context = NULL, \
                }, \
-               vendor, model, \
+               vendor, model, ES51919_CHANNEL_COUNT, \
+               ES51919_COMM_PARAM, ES51919_PACKET_SIZE, \
+               es51919_packet_valid, es51919_packet_parse, \
+               NULL, NULL, es51919_config_list, \
        }).di
 
 SR_REGISTER_DEV_DRIVER_LIST(lcr_es51919_drivers,
diff --git a/src/hardware/serial-lcr/protocol.c b/src/hardware/serial-lcr/protocol.c
new file mode 100644 (file)
index 0000000..ccf8974
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Janne Huttunen <jahuttun@gmail.com>
+ * Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libsigrok/libsigrok.h>
+#include <libsigrok-internal.h>
+#include "protocol.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void send_frame_start(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct lcr_parse_info *info;
+       uint64_t freq;
+       const char *model;
+       struct sr_datafeed_packet packet;
+
+       devc = sdi->priv;
+       info = &devc->parse_info;
+
+       /* Communicate changes of frequency or model before data values. */
+       freq = info->output_freq;
+       if (freq != devc->output_freq) {
+               devc->output_freq = freq;
+               sr_session_send_meta(sdi, SR_CONF_OUTPUT_FREQUENCY,
+                       g_variant_new_double(freq));
+       }
+       model = info->circuit_model;
+       if (model && model != devc->circuit_model) {
+               devc->circuit_model = model;
+               sr_session_send_meta(sdi, SR_CONF_EQUIV_CIRCUIT_MODEL,
+                       g_variant_new_string(model));
+       }
+
+       /* Data is about to get sent. Start a new frame. */
+       packet.type = SR_DF_FRAME_BEGIN;
+       sr_session_send(sdi, &packet);
+}
+
+static void send_frame_end(struct sr_dev_inst *sdi)
+{
+       struct sr_datafeed_packet packet;
+
+       packet.type = SR_DF_FRAME_END;
+       sr_session_send(sdi, &packet);
+}
+
+static int handle_packet(struct sr_dev_inst *sdi, const uint8_t *pkt)
+{
+       struct dev_context *devc;
+       struct lcr_parse_info *info;
+       const struct lcr_info *lcr;
+       size_t ch_idx;
+       int rc;
+       float value;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct sr_analog_encoding encoding;
+       struct sr_analog_meaning meaning;
+       struct sr_analog_spec spec;
+       gboolean frame;
+       struct sr_channel *channel;
+
+       devc = sdi->priv;
+       info = &devc->parse_info;
+       lcr = devc->lcr_info;
+
+       /* Note: digits/spec_digits will be overridden later. */
+       sr_analog_init(&analog, &encoding, &meaning, &spec, 0);
+       analog.num_samples = 1;
+       analog.data = &value;
+
+       frame = FALSE;
+       for (ch_idx = 0; ch_idx < lcr->channel_count; ch_idx++) {
+               channel = g_slist_nth_data(sdi->channels, ch_idx);
+               analog.meaning->channels = g_slist_append(NULL, channel);
+               info->ch_idx = ch_idx;
+               rc = lcr->packet_parse(pkt, &value, &analog, info);
+               if (sdi->session && rc == SR_OK && analog.meaning->mq && channel->enabled) {
+                       if (!frame) {
+                               send_frame_start(sdi);
+                               frame = TRUE;
+                       }
+                       packet.type = SR_DF_ANALOG;
+                       packet.payload = &analog;
+                       sr_session_send(sdi, &packet);
+               }
+               g_slist_free(analog.meaning->channels);
+       }
+       if (frame) {
+               send_frame_end(sdi);
+               sr_sw_limits_update_frames_read(&devc->limits, 1);
+       }
+
+       return SR_OK;
+}
+
+static int handle_new_data(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       ssize_t rdsize;
+       const struct lcr_info *lcr;
+       uint8_t *pkt;
+       size_t copy_len;
+
+       devc = sdi->priv;
+       serial = sdi->conn;
+
+       /* Read another chunk of data into the buffer. */
+       rdsize = sizeof(devc->buf) - devc->buf_rxpos;
+       rdsize = serial_read_nonblocking(serial, &devc->buf[devc->buf_rxpos], rdsize);
+       if (rdsize < 0)
+               return SR_ERR_IO;
+       devc->buf_rxpos += rdsize;
+
+       /*
+        * Process as many packets as the buffer might contain. Assume
+        * that the stream is synchronized in the typical case. Re-sync
+        * in case of mismatch (skip individual bytes until data matches
+        * the expected packet layout again).
+        */
+       lcr = devc->lcr_info;
+       while (devc->buf_rxpos >= lcr->packet_size) {
+               pkt = &devc->buf[0];
+               if (!lcr->packet_valid(pkt)) {
+                       copy_len = devc->buf_rxpos - 1;
+                       memmove(&devc->buf[0], &devc->buf[1], copy_len);
+                       devc->buf_rxpos--;
+                       continue;
+               }
+               (void)handle_packet(sdi, pkt);
+               copy_len = devc->buf_rxpos - lcr->packet_size;
+               memmove(&devc->buf[0], &devc->buf[lcr->packet_size], copy_len);
+               devc->buf_rxpos -= lcr->packet_size;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int lcr_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       if (revents == G_IO_IN)
+               handle_new_data(sdi);
+
+       if (sr_sw_limits_check(&devc->limits))
+               sr_dev_acquisition_stop(sdi);
+
+       return TRUE;
+}
diff --git a/src/hardware/serial-lcr/protocol.h b/src/hardware/serial-lcr/protocol.h
new file mode 100644 (file)
index 0000000..8e11733
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Janne Huttunen <jahuttun@gmail.com>
+ * Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_SERIAL_LCR_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_SERIAL_LCR_PROTOCOL_H
+
+#define LOG_PREFIX "serial-lcr"
+
+#include <libsigrok/libsigrok.h>
+#include <libsigrok-internal.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+struct lcr_info {
+       struct sr_dev_driver di;
+       const char *vendor;
+       const char *model;
+       size_t channel_count;
+       const char *comm;
+       size_t packet_size;
+       gboolean (*packet_valid)(const uint8_t *pkt);
+       int (*packet_parse)(const uint8_t *pkt, float *value,
+               struct sr_datafeed_analog *analog, void *info);
+       int (*config_get)(uint32_t key, GVariant **data,
+               const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg);
+       int (*config_set)(uint32_t key, GVariant *data,
+               const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg);
+       int (*config_list)(uint32_t key, GVariant **data,
+               const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg);
+};
+
+#define LCR_BUFSIZE    128
+
+struct dev_context {
+       const struct lcr_info *lcr_info;
+       struct sr_sw_limits limits;
+       uint8_t buf[LCR_BUFSIZE];
+       size_t buf_rxpos, buf_rdpos;
+       struct lcr_parse_info parse_info;
+       uint64_t output_freq;
+       const char *circuit_model;
+};
+
+SR_PRIV int lcr_receive_data(int fd, int revents, void *cb_data);
+
+#endif
index fad0a3e98f08eb4d2f99fb61b4e5c77ee62d67cb..0695de49dd6d3334d342685fc125611f99cc8efe 100644 (file)
@@ -2,6 +2,7 @@
  * This file is part of the libsigrok project.
  *
  * Copyright (C) 2014 Janne Huttunen <jahuttun@gmail.com>
+ * Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 
 #include <config.h>
-#include <stdint.h>
-#include <string.h>
-#include <math.h>
 #include <glib.h>
 #include <libsigrok/libsigrok.h>
 #include "libsigrok-internal.h"
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
 
 #define LOG_PREFIX "es51919"
 
 #ifdef HAVE_SERIAL_COMM
 
-struct dev_buffer {
-       /** Total size of the buffer. */
-       size_t size;
-       /** Amount of data currently in the buffer. */
-       size_t len;
-       /** Offset where the data starts in the buffer. */
-       size_t offset;
-       /** Space for the data. */
-       uint8_t data[];
-};
-
-static struct dev_buffer *dev_buffer_new(size_t size)
-{
-       struct dev_buffer *dbuf;
-
-       dbuf = g_malloc0(sizeof(struct dev_buffer) + size);
-       dbuf->size = size;
-       dbuf->len = 0;
-       dbuf->offset = 0;
-
-       return dbuf;
-}
-
-static void dev_buffer_destroy(struct dev_buffer *dbuf)
-{
-       g_free(dbuf);
-}
-
-static int dev_buffer_fill_serial(struct dev_buffer *dbuf,
-                                 struct sr_dev_inst *sdi)
-{
-       struct sr_serial_dev_inst *serial;
-       int len;
-
-       serial = sdi->conn;
-
-       /* If we already have data, move it to the beginning of the buffer. */
-       if (dbuf->len > 0 && dbuf->offset > 0)
-               memmove(dbuf->data, dbuf->data + dbuf->offset, dbuf->len);
-
-       dbuf->offset = 0;
-
-       len = dbuf->size - dbuf->len;
-       len = serial_read_nonblocking(serial, dbuf->data + dbuf->len, len);
-       if (len < 0) {
-               sr_err("Serial port read error: %d.", len);
-               return len;
-       }
-
-       dbuf->len += len;
-
-       return SR_OK;
-}
-
-static uint8_t *dev_buffer_packet_find(struct dev_buffer *dbuf,
-                               gboolean (*packet_valid)(const uint8_t *),
-                               size_t packet_size)
-{
-       size_t offset;
-
-       while (dbuf->len >= packet_size) {
-               if (packet_valid(dbuf->data + dbuf->offset)) {
-                       offset = dbuf->offset;
-                       dbuf->offset += packet_size;
-                       dbuf->len -= packet_size;
-                       return dbuf->data + offset;
-               }
-               dbuf->offset++;
-               dbuf->len--;
-       }
-
-       return NULL;
-}
-
-struct dev_limit_counter {
-       /** The current number of received samples/frames/etc. */
-       uint64_t count;
-       /** The limit (in number of samples/frames/etc.). */
-       uint64_t limit;
-};
-
-static void dev_limit_counter_start(struct dev_limit_counter *cnt)
-{
-       cnt->count = 0;
-}
-
-static void dev_limit_counter_inc(struct dev_limit_counter *cnt)
-{
-       cnt->count++;
-}
-
-static void dev_limit_counter_limit_set(struct dev_limit_counter *cnt,
-                                       uint64_t limit)
-{
-       cnt->limit = limit;
-}
-
-static gboolean dev_limit_counter_limit_reached(struct dev_limit_counter *cnt)
-{
-       if (cnt->limit && cnt->count >= cnt->limit) {
-               sr_info("Requested counter limit reached.");
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
-struct dev_time_counter {
-       /** The starting time of current sampling run. */
-       int64_t starttime;
-       /** The time limit (in milliseconds). */
-       uint64_t limit;
-};
-
-static void dev_time_counter_start(struct dev_time_counter *cnt)
-{
-       cnt->starttime = g_get_monotonic_time();
-}
-
-static void dev_time_limit_set(struct dev_time_counter *cnt, uint64_t limit)
-{
-       cnt->limit = limit;
-}
-
-static gboolean dev_time_limit_reached(struct dev_time_counter *cnt)
-{
-       int64_t time;
-
-       if (cnt->limit) {
-               time = (g_get_monotonic_time() - cnt->starttime) / 1000;
-               if (time > (int64_t)cnt->limit) {
-                       sr_info("Requested time limit reached.");
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-static void serial_conf_get(GSList *options, const char *def_serialcomm,
-                           const char **conn, const char **serialcomm)
-{
-       struct sr_config *src;
-       GSList *l;
-
-       *conn = *serialcomm = NULL;
-       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 (*serialcomm == NULL)
-               *serialcomm = def_serialcomm;
-}
-
-static struct sr_serial_dev_inst *serial_dev_new(GSList *options,
-                                                const char *def_serialcomm)
-
-{
-       const char *conn, *serialcomm;
-
-       serial_conf_get(options, def_serialcomm, &conn, &serialcomm);
-
-       if (!conn)
-               return NULL;
-
-       return sr_serial_dev_inst_new(conn, serialcomm);
-}
-
-static int serial_stream_check_buf(struct sr_serial_dev_inst *serial,
-                                  uint8_t *buf, size_t buflen,
-                                  size_t packet_size,
-                                  packet_valid_callback is_valid,
-                                  uint64_t timeout_ms)
-{
-       size_t len, dropped;
-       int ret;
-
-       if ((ret = serial_open(serial, SERIAL_RDWR)) != SR_OK)
-               return ret;
-
-       serial_flush(serial);
-
-       len = buflen;
-       ret = serial_stream_detect(serial, buf, &len, packet_size,
-                                  is_valid, timeout_ms);
-
-       serial_close(serial);
-
-       if (ret != SR_OK)
-               return ret;
-
-       /*
-        * If we dropped more than two packets worth of data, something is
-        * wrong. We shouldn't quit however, since the dropped bytes might be
-        * just zeroes at the beginning of the stream. Those can occur as a
-        * combination of the nonstandard cable that ships with some devices
-        * and the serial port or USB to serial adapter.
-        */
-       dropped = len - packet_size;
-       if (dropped > 2 * packet_size)
-               sr_warn("Had to drop too much data.");
-
-       return SR_OK;
-}
-
-static int serial_stream_check(struct sr_serial_dev_inst *serial,
-                              size_t packet_size,
-                              packet_valid_callback is_valid,
-                              uint64_t timeout_ms)
-{
-       uint8_t buf[128];
-
-       return serial_stream_check_buf(serial, buf, sizeof(buf), packet_size,
-                                      is_valid, timeout_ms);
-}
-
 /*
  * Cyrustek ES51919 LCR chipset host protocol.
  *
@@ -346,32 +123,45 @@ static int serial_stream_check(struct sr_serial_dev_inst *serial,
  * 0x10: footer2 (0x0a) ?
  */
 
-#define PACKET_SIZE 17
-
 static const double frequencies[] = {
-       100, 120, 1000, 10000, 100000, 0,
+       0, 100, 120, 1000, 10000, 100000,
 };
 
-enum { MODEL_NONE, MODEL_PAR, MODEL_SER, MODEL_AUTO, };
-
-static const char *const models[] = {
-       "NONE", "PARALLEL", "SERIES", "AUTO",
+static const size_t freq_code_map[] = {
+       1, 2, 3, 4, 5, 0,
 };
 
-struct dev_context {
-       struct dev_limit_counter frame_count;
+static uint64_t get_frequency(size_t code)
+{
+       uint64_t freq;
 
-       struct dev_time_counter time_count;
+       if (code >= ARRAY_SIZE(freq_code_map)) {
+               sr_err("Unknown output frequency code %zu.", code);
+               return frequencies[0];
+       }
 
-       struct dev_buffer *buf;
+       code = freq_code_map[code];
+       freq = frequencies[code];
 
-       /** The frequency of the test signal (index to frequencies[]). */
-       unsigned int freq;
+       return freq;
+}
 
-       /** Equivalent circuit model (index to models[]). */
-       unsigned int model;
+enum { MODEL_NONE, MODEL_PAR, MODEL_SER, MODEL_AUTO, };
+
+static const char *const circuit_models[] = {
+       "NONE", "PARALLEL", "SERIES", "AUTO",
 };
 
+static const char *get_equiv_model(size_t code)
+{
+       if (code >= ARRAY_SIZE(circuit_models)) {
+               sr_err("Unknown equivalent circuit model code %zu.", code);
+               return "NONE";
+       }
+
+       return circuit_models[code];
+}
+
 static const uint8_t *pkt_to_buf(const uint8_t *pkt, int is_secondary)
 {
        return is_secondary ? pkt + 10 : pkt + 5;
@@ -414,18 +204,22 @@ static int parse_mq(const uint8_t *pkt, int is_secondary, int is_parallel)
 static float parse_value(const uint8_t *buf, int *digits)
 {
        static const int exponents[] = {0, -1, -2, -3, -4, -5, -6, -7};
+
        int exponent;
        int16_t val;
+       float fval;
 
        exponent = exponents[buf[3] & 7];
        *digits = -exponent;
        val = (buf[1] << 8) | buf[2];
-       return (float)val * powf(10, exponent);
+       fval = (float)val;
+       fval *= powf(10, exponent);
+
+       return fval;
 }
 
 static void parse_measurement(const uint8_t *pkt, float *floatval,
-                             struct sr_datafeed_analog *analog,
-                             int is_secondary)
+       struct sr_datafeed_analog *analog, int is_secondary)
 {
        static const struct {
                int unit;
@@ -447,6 +241,7 @@ static void parse_measurement(const uint8_t *pkt, float *floatval,
                { SR_UNIT_PERCENTAGE, 0 }, /* % */
                { SR_UNIT_DEGREE,     0 }, /* degree */
        };
+
        const uint8_t *buf;
        int digits, exponent;
        int state;
@@ -494,366 +289,80 @@ static void parse_measurement(const uint8_t *pkt, float *floatval,
        analog->spec->spec_digits = digits - exponent;
 }
 
-static unsigned int parse_freq(const uint8_t *pkt)
+static uint64_t parse_freq(const uint8_t *pkt)
 {
-       unsigned int freq;
-
-       freq = pkt[3] >> 5;
-
-       if (freq >= ARRAY_SIZE(frequencies)) {
-               sr_err("Unknown frequency %u.", freq);
-               freq = ARRAY_SIZE(frequencies) - 1;
-       }
-
-       return freq;
+       return get_frequency(pkt[3] >> 5);
 }
 
-static unsigned int parse_model(const uint8_t *pkt)
+static const char *parse_model(const uint8_t *pkt)
 {
+       size_t code;
+
        if (pkt[2] & 0x40)
-               return MODEL_AUTO;
+               code = MODEL_AUTO;
        else if (parse_mq(pkt, 0, 0) == SR_MQ_RESISTANCE)
-               return MODEL_NONE;
-       else if (pkt[2] & 0x80)
-               return MODEL_PAR;
+               code = MODEL_NONE;
        else
-               return MODEL_SER;
-}
-
-static gboolean packet_valid(const uint8_t *pkt)
-{
-       /*
-        * If the first two bytes of the packet are indeed a constant
-        * header, they should be checked too. Since we don't know it
-        * for sure, we'll just check the last two for now since they
-        * seem to be constant just like in the other Cyrustek chipset
-        * protocols.
-        */
-       if (pkt[15] == 0xd && pkt[16] == 0xa)
-               return TRUE;
-
-       return FALSE;
-}
+               code = (pkt[2] & 0x80) ? MODEL_PAR : MODEL_SER;
 
-static int send_freq_update(struct sr_dev_inst *sdi, unsigned int freq)
-{
-       return sr_session_send_meta(sdi, SR_CONF_OUTPUT_FREQUENCY,
-                               g_variant_new_double(frequencies[freq]));
-}
-
-static int send_model_update(struct sr_dev_inst *sdi, unsigned int model)
-{
-       return sr_session_send_meta(sdi, SR_CONF_EQUIV_CIRCUIT_MODEL,
-                               g_variant_new_string(models[model]));
+       return get_equiv_model(code);
 }
 
-static void handle_packet(struct sr_dev_inst *sdi, const uint8_t *pkt)
+SR_PRIV gboolean es51919_packet_valid(const uint8_t *pkt)
 {
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct sr_analog_encoding encoding;
-       struct sr_analog_meaning meaning;
-       struct sr_analog_spec spec;
-       struct dev_context *devc;
-       unsigned int val;
-       float floatval;
-       gboolean frame;
-       struct sr_channel *channel;
-
-       devc = sdi->priv;
-
-       val = parse_freq(pkt);
-       if (val != devc->freq) {
-               if (send_freq_update(sdi, val) == SR_OK)
-                       devc->freq = val;
-               else
-                       return;
-       }
-
-       val = parse_model(pkt);
-       if (val != devc->model) {
-               if (send_model_update(sdi, val) == SR_OK)
-                       devc->model = val;
-               else
-                       return;
-       }
 
-       frame = FALSE;
+       /* Check for fixed 0x00 0x0d prefix. */
+       if (pkt[0] != 0x00 || pkt[1] != 0x0d)
+               return FALSE;
 
-       /* Note: digits/spec_digits will be overridden later. */
-       sr_analog_init(&analog, &encoding, &meaning, &spec, 0);
-
-       analog.num_samples = 1;
-       analog.data = &floatval;
-
-       channel = sdi->channels->data;
-       analog.meaning->channels = g_slist_append(NULL, channel);
-
-       parse_measurement(pkt, &floatval, &analog, 0);
-       if (analog.meaning->mq != 0 && channel->enabled) {
-               if (!frame) {
-                       packet.type = SR_DF_FRAME_BEGIN;
-                       sr_session_send(sdi, &packet);
-                       frame = TRUE;
-               }
-
-               packet.type = SR_DF_ANALOG;
-               packet.payload = &analog;
-
-               sr_session_send(sdi, &packet);
-       }
-
-       g_slist_free(analog.meaning->channels);
-
-       channel = sdi->channels->next->data;
-       analog.meaning->channels = g_slist_append(NULL, channel);
-
-       parse_measurement(pkt, &floatval, &analog, 1);
-       if (analog.meaning->mq != 0 && channel->enabled) {
-               if (!frame) {
-                       packet.type = SR_DF_FRAME_BEGIN;
-                       sr_session_send(sdi, &packet);
-                       frame = TRUE;
-               }
-
-               packet.type = SR_DF_ANALOG;
-               packet.payload = &analog;
-
-               sr_session_send(sdi, &packet);
-       }
-
-       g_slist_free(analog.meaning->channels);
-
-       if (frame) {
-               packet.type = SR_DF_FRAME_END;
-               sr_session_send(sdi, &packet);
-               dev_limit_counter_inc(&devc->frame_count);
-       }
-}
-
-static int handle_new_data(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       uint8_t *pkt;
-       int ret;
-
-       devc = sdi->priv;
-
-       ret = dev_buffer_fill_serial(devc->buf, sdi);
-       if (ret < 0)
-               return ret;
-
-       while ((pkt = dev_buffer_packet_find(devc->buf, packet_valid,
-                                            PACKET_SIZE)))
-               handle_packet(sdi, pkt);
-
-       return SR_OK;
-}
-
-static int receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       if (revents == G_IO_IN) {
-               /* Serial data arrived. */
-               handle_new_data(sdi);
-       }
-
-       if (dev_limit_counter_limit_reached(&devc->frame_count) ||
-           dev_time_limit_reached(&devc->time_count))
-               sr_dev_acquisition_stop(sdi);
+       /* Check for fixed 0x0d 0x0a suffix. */
+       if (pkt[15] != 0x0d || pkt[16] != 0x0a)
+               return FALSE;
 
+       /* Packet appears to be valid. */
        return TRUE;
 }
 
-static const char *const channel_names[] = { "P1", "P2" };
-
-static int setup_channels(struct sr_dev_inst *sdi)
+SR_PRIV int es51919_packet_parse(const uint8_t *pkt, float *val,
+       struct sr_datafeed_analog *analog, void *info)
 {
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(channel_names); i++)
-               sr_channel_new(sdi, i, SR_CHANNEL_ANALOG, TRUE, channel_names[i]);
-
-       return SR_OK;
-}
-
-SR_PRIV void es51919_serial_clean(void *priv)
-{
-       struct dev_context *devc;
-
-       if (!(devc = priv))
-               return;
+       struct lcr_parse_info *parse_info;
 
-       dev_buffer_destroy(devc->buf);
-}
-
-SR_PRIV struct sr_dev_inst *es51919_serial_scan(GSList *options,
-                                               const char *vendor,
-                                               const char *model)
-{
-       struct sr_serial_dev_inst *serial;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       int ret;
-
-       serial = NULL;
-       sdi = NULL;
-       devc = NULL;
-
-       if (!(serial = serial_dev_new(options, "9600/8n1/rts=1/dtr=1")))
-               goto scan_cleanup;
-
-       ret = serial_stream_check(serial, PACKET_SIZE, packet_valid, 3000);
-       if (ret != SR_OK)
-               goto scan_cleanup;
-
-       sr_info("Found device on port %s.", serial->port);
-
-       sdi = g_malloc0(sizeof(struct sr_dev_inst));
-       sdi->status = SR_ST_INACTIVE;
-       sdi->vendor = g_strdup(vendor);
-       sdi->model = g_strdup(model);
-       devc = g_malloc0(sizeof(struct dev_context));
-       devc->buf = dev_buffer_new(PACKET_SIZE * 8);
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-       sdi->priv = devc;
-
-       if (setup_channels(sdi) != SR_OK)
-               goto scan_cleanup;
-
-       return sdi;
-
-scan_cleanup:
-       es51919_serial_clean(devc);
-       sr_dev_inst_free(sdi);
-       sr_serial_dev_inst_free(serial);
-
-       return NULL;
-}
-
-SR_PRIV int es51919_serial_config_get(uint32_t key, GVariant **data,
-                                     const struct sr_dev_inst *sdi,
-                                     const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       devc = sdi->priv;
-
-       switch (key) {
-       case SR_CONF_OUTPUT_FREQUENCY:
-               *data = g_variant_new_double(frequencies[devc->freq]);
-               break;
-       case SR_CONF_EQUIV_CIRCUIT_MODEL:
-               *data = g_variant_new_string(models[devc->model]);
-               break;
-       default:
-               return SR_ERR_NA;
+       parse_info = info;
+       if (!parse_info->ch_idx) {
+               parse_info->output_freq = parse_freq(pkt);
+               parse_info->circuit_model = parse_model(pkt);
        }
+       if (val && analog)
+               parse_measurement(pkt, val, analog, parse_info->ch_idx == 1);
 
        return SR_OK;
 }
 
-SR_PRIV int es51919_serial_config_set(uint32_t key, GVariant *data,
-                                     const struct sr_dev_inst *sdi,
-                                     const struct sr_channel_group *cg)
+/*
+ * These are the get/set/list routines for the _chip_ specific parameters,
+ * the _device_ driver resides in src/hardware/serial-lcr/ instead.
+ */
+
+SR_PRIV int es51919_config_list(uint32_t key, GVariant **data,
+       const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
 {
-       struct dev_context *devc;
-       uint64_t val;
 
+       (void)sdi;
        (void)cg;
 
-       if (!(devc = sdi->priv))
-               return SR_ERR_BUG;
-
        switch (key) {
-       case SR_CONF_LIMIT_MSEC:
-               val = g_variant_get_uint64(data);
-               dev_time_limit_set(&devc->time_count, val);
-               sr_dbg("Setting time limit to %" PRIu64 ".", val);
-               break;
-       case SR_CONF_LIMIT_FRAMES:
-               val = g_variant_get_uint64(data);
-               dev_limit_counter_limit_set(&devc->frame_count, val);
-               sr_dbg("Setting frame limit to %" PRIu64 ".", val);
-               break;
-       default:
-               sr_spew("%s: Unsupported key %u", __func__, key);
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static const uint32_t scanopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const uint32_t drvopts[] = {
-       SR_CONF_LCRMETER,
-};
-
-static const uint32_t devopts[] = {
-       SR_CONF_CONTINUOUS,
-       SR_CONF_LIMIT_FRAMES | 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,
-};
-
-SR_PRIV int es51919_serial_config_list(uint32_t key, GVariant **data,
-                                      const struct sr_dev_inst *sdi,
-                                      const struct sr_channel_group *cg)
-{
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
-       case SR_CONF_DEVICE_OPTIONS:
-               return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
        case SR_CONF_OUTPUT_FREQUENCY:
                *data = g_variant_new_fixed_array(G_VARIANT_TYPE_DOUBLE,
                        ARRAY_AND_SIZE(frequencies), sizeof(double));
-               break;
+               return SR_OK;
        case SR_CONF_EQUIV_CIRCUIT_MODEL:
-               *data = g_variant_new_strv(ARRAY_AND_SIZE(models));
-               break;
+               *data = g_variant_new_strv(ARRAY_AND_SIZE(circuit_models));
+               return SR_OK;
        default:
                return SR_ERR_NA;
        }
-
-       return SR_OK;
-}
-
-SR_PRIV int es51919_serial_acquisition_start(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR_BUG;
-
-       dev_limit_counter_start(&devc->frame_count);
-       dev_time_counter_start(&devc->time_count);
-
-       std_session_send_df_header(sdi);
-
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 50,
-                         receive_data, (void *)sdi);
-
-       return SR_OK;
+       /* UNREACH */
 }
 
 #endif
index c79524cf1c056f6cb075e18d8a42ce57940c9964..0dfacbce1f09188fde9b0e0dca99893a277b7ff1 100644 (file)
@@ -1619,21 +1619,26 @@ SR_PRIV int sr_vc96_parse(const uint8_t *buf, float *floatval,
 
 /*--- lcr/es51919.c ---------------------------------------------------------*/
 
-SR_PRIV void es51919_serial_clean(void *priv);
-SR_PRIV struct sr_dev_inst *es51919_serial_scan(GSList *options,
-                                               const char *vendor,
-                                               const char *model);
-SR_PRIV int es51919_serial_config_get(uint32_t key, GVariant **data,
-                                     const struct sr_dev_inst *sdi,
-                                     const struct sr_channel_group *cg);
-SR_PRIV int es51919_serial_config_set(uint32_t key, GVariant *data,
-                                     const struct sr_dev_inst *sdi,
-                                     const struct sr_channel_group *cg);
-SR_PRIV int es51919_serial_config_list(uint32_t key, GVariant **data,
-                                      const struct sr_dev_inst *sdi,
-                                      const struct sr_channel_group *cg);
-SR_PRIV int es51919_serial_acquisition_start(const struct sr_dev_inst *sdi);
-SR_PRIV int es51919_serial_acquisition_stop(struct sr_dev_inst *sdi);
+/* Acquisition details which apply to all supported serial-lcr devices. */
+struct lcr_parse_info {
+       size_t ch_idx;
+       uint64_t output_freq;
+       const char *circuit_model;
+};
+
+#define ES51919_PACKET_SIZE    17
+#define ES51919_CHANNEL_COUNT  2
+#define ES51919_COMM_PARAM     "9600/8n1/rts=1/dtr=1"
+
+SR_PRIV int es51919_config_get(uint32_t key, GVariant **data,
+       const struct sr_dev_inst *sdi, const struct sr_channel_group *cg);
+SR_PRIV int es51919_config_set(uint32_t key, GVariant *data,
+       const struct sr_dev_inst *sdi, const struct sr_channel_group *cg);
+SR_PRIV int es51919_config_list(uint32_t key, GVariant **data,
+       const struct sr_dev_inst *sdi, const struct sr_channel_group *cg);
+SR_PRIV gboolean es51919_packet_valid(const uint8_t *pkt);
+SR_PRIV int es51919_packet_parse(const uint8_t *pkt, float *floatval,
+       struct sr_datafeed_analog *analog, void *info);
 
 /*--- dmm/ut372.c -----------------------------------------------------------*/