]> sigrok.org Git - libsigrok.git/commitdiff
korad-kdxxxxp: Rename driver to korad-kaxxxxp.
authorUwe Hermann <redacted>
Thu, 26 Nov 2015 23:16:05 +0000 (00:16 +0100)
committerUwe Hermann <redacted>
Thu, 26 Nov 2015 23:54:07 +0000 (00:54 +0100)
This matches the supported / supportable devices better.

Makefile.am
configure.ac
src/drivers.c
src/hardware/korad-kaxxxxp/api.c [new file with mode: 0644]
src/hardware/korad-kaxxxxp/protocol.c [new file with mode: 0644]
src/hardware/korad-kaxxxxp/protocol.h [new file with mode: 0644]
src/hardware/korad-kdxxxxp/api.c [deleted file]
src/hardware/korad-kdxxxxp/protocol.c [deleted file]
src/hardware/korad-kdxxxxp/protocol.h [deleted file]

index 4ea3b8a1f9c18359335a0ca70b36de7fbf6e579f..4ed41bf7b63e500de698162f0d4d0cd78c2a9172 100644 (file)
@@ -323,11 +323,11 @@ libsigrok_la_SOURCES += \
        src/hardware/kern-scale/protocol.c \
        src/hardware/kern-scale/api.c
 endif
        src/hardware/kern-scale/protocol.c \
        src/hardware/kern-scale/api.c
 endif
-if HW_KORAD_KDXXXXP
+if HW_KORAD_KAXXXXP
 libsigrok_la_SOURCES += \
 libsigrok_la_SOURCES += \
-       src/hardware/korad-kdxxxxp/protocol.h \
-       src/hardware/korad-kdxxxxp/protocol.c \
-       src/hardware/korad-kdxxxxp/api.c
+       src/hardware/korad-kaxxxxp/protocol.h \
+       src/hardware/korad-kaxxxxp/protocol.c \
+       src/hardware/korad-kaxxxxp/api.c
 endif
 if HW_LASCAR_EL_USB
 libsigrok_la_SOURCES += \
 endif
 if HW_LASCAR_EL_USB
 libsigrok_la_SOURCES += \
index e5d5ce8c6f56392e02f8e6965255a2fede2b41dc..ac7259d3f06ef48a0a0070c70be1ba5786941f73 100644 (file)
@@ -239,7 +239,7 @@ SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb])
 SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi])
 SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb])
 SR_DRIVER([KERN scale], [kern-scale], [libserialport])
 SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi])
 SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb])
 SR_DRIVER([KERN scale], [kern-scale], [libserialport])
-SR_DRIVER([Korad KDxxxxP], [korad-kdxxxxp], [libserialport])
+SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [libserialport])
 SR_DRIVER([Lascar EL-USB], [lascar-el-usb], [libusb])
 SR_DRIVER([Manson HCS-3xxx], [manson-hcs-3xxx], [libserialport])
 SR_DRIVER([maynuo-m97], [maynuo-m97])
 SR_DRIVER([Lascar EL-USB], [lascar-el-usb], [libusb])
 SR_DRIVER([Manson HCS-3xxx], [manson-hcs-3xxx], [libserialport])
 SR_DRIVER([maynuo-m97], [maynuo-m97])
index fd4b91fe0255141d8ce3c4f69325c7efdcbf24ac..f4e5d1c39a5f0fcfbdcca05427f15f852c3a63f3 100644 (file)
@@ -102,8 +102,8 @@ extern SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info;
 #ifdef HAVE_HW_KERN_SCALE
 extern SR_PRIV struct sr_dev_driver *kern_scale_drivers[];
 #endif
 #ifdef HAVE_HW_KERN_SCALE
 extern SR_PRIV struct sr_dev_driver *kern_scale_drivers[];
 #endif
-#ifdef HAVE_HW_KORAD_KDXXXXP
-extern SR_PRIV struct sr_dev_driver korad_kdxxxxp_driver_info;
+#ifdef HAVE_HW_KORAD_KAXXXXP
+extern SR_PRIV struct sr_dev_driver korad_kaxxxxp_driver_info;
 #endif
 #ifdef HAVE_HW_LASCAR_EL_USB
 extern SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info;
 #endif
 #ifdef HAVE_HW_LASCAR_EL_USB
 extern SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info;
@@ -263,8 +263,8 @@ SR_PRIV struct sr_dev_driver **drivers_lists[] = {
 #ifdef HAVE_HW_KERN_SCALE
        kern_scale_drivers,
 #endif
 #ifdef HAVE_HW_KERN_SCALE
        kern_scale_drivers,
 #endif
-#ifdef HAVE_HW_KORAD_KDXXXXP
-       (DRVS) {&korad_kdxxxxp_driver_info, NULL},
+#ifdef HAVE_HW_KORAD_KAXXXXP
+       (DRVS) {&korad_kaxxxxp_driver_info, NULL},
 #endif
 #ifdef HAVE_HW_LASCAR_EL_USB
        (DRVS) {&lascar_el_usb_driver_info, NULL},
 #endif
 #ifdef HAVE_HW_LASCAR_EL_USB
        (DRVS) {&lascar_el_usb_driver_info, NULL},
diff --git a/src/hardware/korad-kaxxxxp/api.c b/src/hardware/korad-kaxxxxp/api.c
new file mode 100644 (file)
index 0000000..c195f1f
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
+ *
+ * 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 <config.h>
+#include "protocol.h"
+
+static const uint32_t drvopts[] = {
+       /* Device class */
+       SR_CONF_POWER_SUPPLY,
+};
+
+static const uint32_t scanopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const uint32_t devopts[] = {
+       /* Device class */
+       SR_CONF_POWER_SUPPLY,
+       /* Acquisition modes. */
+       SR_CONF_CONTINUOUS,
+       SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
+       SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
+       /* Device configuration */
+       SR_CONF_VOLTAGE | SR_CONF_GET,
+       SR_CONF_VOLTAGE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+       SR_CONF_CURRENT | SR_CONF_GET,
+       SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+       SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
+       SR_CONF_REGULATION | SR_CONF_GET,
+       SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_GET | SR_CONF_SET,
+       SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED | SR_CONF_GET | SR_CONF_SET,
+};
+
+static const struct korad_kaxxxxp_model models[] = {
+       /* Device enum, vendor, model, ID reply, channels, voltage, current */
+       {VELLEMAN_LABPS_3005D, "Velleman", "LABPS3005D",
+               "VELLEMANLABPS3005DV2.0", 1, {0, 31, 0.01}, {0, 5, 0.001}},
+       {0, NULL, NULL, NULL, 0, {0, 0, 0}, {0, 0, 0}}
+};
+
+SR_PRIV struct sr_dev_driver korad_kaxxxxp_driver_info;
+
+static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(struct sr_dev_driver *di, GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       GSList *devices, *l;
+       struct sr_dev_inst *sdi;
+       struct sr_config *src;
+       const char *conn, *serialcomm;
+       struct sr_serial_dev_inst *serial;
+       char reply[50];
+       int i, model_id;
+       unsigned int len;
+
+       devices = NULL;
+       conn = NULL;
+       serialcomm = NULL;
+       drvc = di->context;
+       drvc->instances = 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;
+               default:
+                       sr_err("Unknown option %d, skipping.", src->key);
+                       break;
+               }
+       }
+
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = "9600/8n1";
+
+       serial = sr_serial_dev_inst_new(conn, serialcomm);
+       if (serial_open(serial, SERIAL_RDWR) != SR_OK)
+               return NULL;
+
+       serial_flush(serial);
+
+       /* Get the device model. */
+       len = 0;
+       for (i = 0; models[i].id; i++) {
+               if (strlen(models[i].id) > len)
+                       len = strlen(models[i].id);
+       }
+       memset(&reply, 0, sizeof(reply));
+       sr_dbg("Want max %d bytes.", len);
+       if ((korad_kaxxxxp_send_cmd(serial, "*IDN?") < 0))
+               return NULL;
+
+       /* i is used here for debug purposes only. */
+       if ((i = korad_kaxxxxp_read_chars(serial, len, reply)) < 0)
+               return NULL;
+       sr_dbg("Received: %d, %s", i, reply);
+       model_id = -1;
+       for (i = 0; models[i].id; i++) {
+               if (!strcmp(models[i].id, reply))
+                       model_id = i;
+       }
+       if (model_id < 0) {
+               sr_err("Unknown model ID '%s' detected, aborting.", reply);
+               return NULL;
+       }
+       sr_dbg("Found: %s %s", models[model_id].vendor, models[model_id].name);
+
+       /* Init device instance, etc. */
+       sdi = g_malloc0(sizeof(struct sr_dev_inst));
+       sdi->status = SR_ST_INACTIVE;
+       sdi->vendor = g_strdup(models[model_id].vendor);
+       sdi->model = g_strdup(models[model_id].name);
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+       sdi->driver = di;
+
+       sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "CH1");
+
+       devc = g_malloc0(sizeof(struct dev_context));
+       devc->model = &models[model_id];
+       devc->reply[5] = 0;
+       devc->req_sent_at = 0;
+       sdi->priv = devc;
+
+       /* Get current status of device. */
+       if (korad_kaxxxxp_get_all_values(serial, devc) < 0)
+               goto exit_err;
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+       serial_close(serial);
+       if (!devices)
+               sr_serial_dev_inst_free(serial);
+
+       return devices;
+
+exit_err:
+       sr_dev_inst_free(sdi);
+       g_free(devc);
+       sr_dbg("Scan failed.");
+
+       return NULL;
+}
+
+static GSList *dev_list(const struct sr_dev_driver *di)
+{
+       return ((struct drv_context *)(di->context))->instances;
+}
+
+static int dev_clear(const struct sr_dev_driver *di)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int cleanup(const struct sr_dev_driver *di)
+{
+       dev_clear(di);
+       return SR_OK;
+}
+
+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;
+
+       (void)cg;
+
+       if (!sdi || !data)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               *data = g_variant_new_uint64(devc->limit_msec);
+               break;
+       case SR_CONF_VOLTAGE:
+               *data = g_variant_new_double(devc->voltage);
+               break;
+       case SR_CONF_VOLTAGE_TARGET:
+               *data = g_variant_new_double(devc->voltage_max);
+               break;
+       case SR_CONF_CURRENT:
+               *data = g_variant_new_double(devc->current);
+               break;
+       case SR_CONF_CURRENT_LIMIT:
+               *data = g_variant_new_double(devc->current_max);
+               break;
+       case SR_CONF_ENABLED:
+               *data = g_variant_new_boolean(devc->output_enabled);
+               break;
+       case SR_CONF_REGULATION:
+               /* Dual channel not supported. */
+               *data = g_variant_new_string((devc->cc_mode[0]) ? "CC" : "CV");
+               break;
+       case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
+               *data = g_variant_new_boolean(devc->ocp_enabled);
+               break;
+       case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
+               *data = g_variant_new_boolean(devc->ovp_enabled);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+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;
+       double dval;
+       gboolean bval;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_LIMIT_MSEC:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_msec = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_samples = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_VOLTAGE_TARGET:
+               dval = g_variant_get_double(data);
+               if (dval < devc->model->voltage[0] || dval > devc->model->voltage[1])
+                       return SR_ERR_ARG;
+               devc->voltage_max = dval;
+               devc->target = KAXXXXP_VOLTAGE_MAX;
+               if (korad_kaxxxxp_set_value(sdi->conn, devc) < 0)
+                       return SR_ERR;
+               break;
+       case SR_CONF_CURRENT_LIMIT:
+               dval = g_variant_get_double(data);
+               if (dval < devc->model->current[0] || dval > devc->model->current[1])
+                       return SR_ERR_ARG;
+               devc->current_max = dval;
+               devc->target = KAXXXXP_CURRENT_MAX;
+               if (korad_kaxxxxp_set_value(sdi->conn, devc) < 0)
+                       return SR_ERR;
+               break;
+       case SR_CONF_ENABLED:
+               bval = g_variant_get_boolean(data);
+               /* Set always so it is possible turn off with sigrok-cli. */
+               devc->output_enabled = bval;
+               devc->target = KAXXXXP_OUTPUT;
+               if (korad_kaxxxxp_set_value(sdi->conn, devc) < 0)
+                       return SR_ERR;
+               break;
+       case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
+               bval = g_variant_get_boolean(data);
+               devc->ocp_enabled = bval;
+               devc->target = KAXXXXP_OCP;
+               if (korad_kaxxxxp_set_value(sdi->conn, devc) < 0)
+                       return SR_ERR;
+               break;
+       case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
+               bval = g_variant_get_boolean(data);
+               devc->ovp_enabled = bval;
+               devc->target = KAXXXXP_OVP;
+               if (korad_kaxxxxp_set_value(sdi->conn, devc) < 0)
+                       return SR_ERR;
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+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;
+       GVariant *gvar;
+       GVariantBuilder gvb;
+       double dval;
+       int idx;
+
+       (void)cg;
+
+       /* Always available (with or without sdi). */
+       if (key == SR_CONF_SCAN_OPTIONS) {
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+                       scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
+               return SR_OK;
+       }
+
+       /* Return drvopts without sdi (and devopts with sdi, see below). */
+       if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+                       drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
+               return SR_OK;
+       }
+
+       /* Every other key needs an sdi. */
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+                       devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
+               break;
+       case SR_CONF_VOLTAGE_TARGET:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               /* Min, max, step. */
+               for (idx = 0; idx < 3; idx++) {
+                       dval = devc->model->voltage[idx];
+                       gvar = g_variant_new_double(dval);
+                       g_variant_builder_add_value(&gvb, gvar);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_CURRENT_LIMIT:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               /* Min, max, step. */
+               for (idx = 0; idx < 3; idx++) {
+                       dval = devc->model->current[idx];
+                       gvar = g_variant_new_double(dval);
+                       g_variant_builder_add_value(&gvb, gvar);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       devc->starttime = g_get_monotonic_time();
+       devc->num_samples = 0;
+       devc->reply_pending = FALSE;
+       devc->req_sent_at = 0;
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN,
+                       KAXXXXP_POLL_INTERVAL_MS,
+                       korad_kaxxxxp_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       return std_serial_dev_acquisition_stop(sdi, cb_data,
+               std_serial_dev_close, sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver korad_kaxxxxp_driver_info = {
+       .name = "korad-kaxxxxp",
+       .longname = "Korad KAxxxxP",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = 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 = dev_acquisition_stop,
+       .context = NULL,
+};
diff --git a/src/hardware/korad-kaxxxxp/protocol.c b/src/hardware/korad-kaxxxxp/protocol.c
new file mode 100644 (file)
index 0000000..c01d3ca
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
+ *
+ * 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 <config.h>
+#include "protocol.h"
+
+#define REQ_TIMEOUT_MS 500
+#define DEVICE_PROCESSING_TIME_MS 80
+
+SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
+                               const char *cmd)
+{
+       int ret;
+
+       sr_dbg("Sending '%s'.", cmd);
+       if ((ret = serial_write_blocking(serial, cmd, strlen(cmd), 0)) < 0) {
+               sr_err("Error sending command: %d.", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+SR_PRIV int korad_kaxxxxp_read_chars(struct sr_serial_dev_inst *serial,
+                               int count, char *buf)
+{
+       int ret, received, turns;
+
+       received = 0;
+       turns = 0;
+
+       do {
+               if ((ret = serial_read_blocking(serial, buf + received,
+                               count - received,
+                               serial_timeout(serial, count))) < 0) {
+                       sr_err("Error %d reading %d bytes from device.",
+                              ret, count);
+                       return ret;
+               }
+               received += ret;
+               turns++;
+       } while ((received < count) && (turns < 100));
+
+       buf[count] = 0;
+
+       sr_spew("Received: '%s'.", buf);
+
+       return ret;
+}
+
+static void give_device_time_to_process(struct dev_context *devc)
+{
+       int64_t sleeping_time;
+
+       sleeping_time = devc->req_sent_at + (DEVICE_PROCESSING_TIME_MS * 1000);
+       sleeping_time -= g_get_monotonic_time();
+
+       if (sleeping_time > 0) {
+               g_usleep(sleeping_time);
+               sr_spew("Sleeping for processing %" PRIi64 " usec", sleeping_time);
+       }
+}
+
+SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
+                               struct dev_context *devc)
+{
+       char msg[21];
+       const char *cmd;
+       float value;
+       int ret;
+
+       give_device_time_to_process(devc);
+
+       msg[20] = 0;
+       switch(devc->target){
+       case KAXXXXP_CURRENT:
+       case KAXXXXP_VOLTAGE:
+       case KAXXXXP_STATUS:
+               sr_err("Can't set measurable parameter.");
+               return SR_ERR;
+       case KAXXXXP_CURRENT_MAX:
+               cmd = "ISET1:%05.3f";
+               value = devc->current_max;
+               break;
+       case KAXXXXP_VOLTAGE_MAX:
+               cmd = "VSET1:%05.2f";
+               value = devc->voltage_max;
+               break;
+       case KAXXXXP_OUTPUT:
+               cmd = "OUT%01.0f";
+               value = (devc->output_enabled) ? 1 : 0;
+               break;
+       case KAXXXXP_BEEP:
+               cmd = "BEEP%01.0f";
+               value = (devc->beep_enabled) ? 1 : 0;
+               break;
+       case KAXXXXP_OCP:
+               cmd = "OCP%01.0f";
+               value = (devc->ocp_enabled) ? 1 : 0;
+               break;
+       case KAXXXXP_OVP:
+               cmd = "OVP%01.0f";
+               value = (devc->ovp_enabled) ? 1 : 0;
+               break;
+       case KAXXXXP_SAVE:
+               cmd = "SAV%01.0f";
+               if (devc->program < 1 || devc->program > 5) {
+                       sr_err("Only programs 1-5 supported and %d isn't "
+                              "between them.", devc->program);
+                       return SR_ERR;
+               }
+               value = devc->program;
+               break;
+       case KAXXXXP_RECALL:
+               cmd = "RCL%01.0f";
+               if (devc->program < 1 || devc->program > 5) {
+                       sr_err("Only programs 1-5 supported and %d isn't "
+                              "between them.", devc->program);
+                       return SR_ERR;
+               }
+               value = devc->program;
+               break;
+       default:
+               sr_err("Don't know how to set %d.", devc->target);
+               return SR_ERR;
+       }
+
+       if (cmd)
+               snprintf(msg, 20, cmd, value);
+
+       ret = korad_kaxxxxp_send_cmd(serial, msg);
+       devc->req_sent_at = g_get_monotonic_time();
+       devc->reply_pending = FALSE;
+
+       return ret;
+}
+
+SR_PRIV int korad_kaxxxxp_query_value(struct sr_serial_dev_inst *serial,
+                               struct dev_context *devc)
+{
+       int ret;
+
+       give_device_time_to_process(devc);
+
+       switch(devc->target){
+       case KAXXXXP_CURRENT:
+               /* Read current from device. */
+               ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?");
+               break;
+       case KAXXXXP_CURRENT_MAX:
+               /* Read set current from device. */
+               ret = korad_kaxxxxp_send_cmd(serial, "ISET1?");
+               break;
+       case KAXXXXP_VOLTAGE:
+               /* Read voltage from device. */
+               ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?");
+               break;
+       case KAXXXXP_VOLTAGE_MAX:
+               /* Read set voltage from device. */
+               ret = korad_kaxxxxp_send_cmd(serial, "VSET1?");
+               break;
+       case KAXXXXP_STATUS:
+       case KAXXXXP_OUTPUT:
+               /* Read status from device. */
+               ret = korad_kaxxxxp_send_cmd(serial, "STATUS?");
+               break;
+       default:
+               sr_err("Don't know how to query %d.", devc->target);
+               return SR_ERR;
+       }
+
+       devc->req_sent_at = g_get_monotonic_time();
+       devc->reply_pending = TRUE;
+
+       return ret;
+}
+
+SR_PRIV int korad_kaxxxxp_get_all_values(struct sr_serial_dev_inst *serial,
+                               struct dev_context *devc)
+{
+       int ret;
+
+       for (devc->target = KAXXXXP_CURRENT;
+                       devc->target <= KAXXXXP_STATUS; devc->target++) {
+               if ((ret = korad_kaxxxxp_query_value(serial, devc)) < 0)
+                       return ret;
+               if ((ret = korad_kaxxxxp_get_reply(serial, devc)) < 0)
+                       return ret;
+       }
+
+       return ret;
+}
+
+SR_PRIV int korad_kaxxxxp_get_reply(struct sr_serial_dev_inst *serial,
+                               struct dev_context *devc)
+{
+       double value;
+       int count, ret, i;
+       float *target;
+       char status_byte;
+
+       target = NULL;
+       count = 5;
+
+       switch (devc->target) {
+       case KAXXXXP_CURRENT:
+               /* Read current from device. */
+               target = &(devc->current);
+               break;
+       case KAXXXXP_CURRENT_MAX:
+               /* Read set current from device. */
+               target = &(devc->current_max);
+               break;
+       case KAXXXXP_VOLTAGE:
+               /* Read voltage from device. */
+               target = &(devc->voltage);
+               break;
+       case KAXXXXP_VOLTAGE_MAX:
+               /* Read set voltage from device. */
+               target = &(devc->voltage_max);
+               break;
+       case KAXXXXP_STATUS:
+       case KAXXXXP_OUTPUT:
+               /* Read status from device. */
+               count = 1;
+               break;
+       default:
+               sr_err("Don't know where to put repply %d.", devc->target);
+       }
+
+       if ((ret = korad_kaxxxxp_read_chars(serial, count, devc->reply)) < 0)
+               return ret;
+
+       devc->reply[count] = 0;
+
+       if (target) {
+               /* Handle the strange 'M'. */
+               if (devc->reply[0] == 'M') {
+                       for (i = 1; i < count; i++)
+                               devc->reply[i - 1] = devc->reply[i];
+                       /* Get the last character. */
+                       if ((i = korad_kaxxxxp_read_chars(serial, 1,
+                                               &(devc->reply[count]))) < 0)
+                               return i;
+               }
+               value = g_ascii_strtod(devc->reply, NULL);
+               *target = (float)value;
+               sr_dbg("value: %f",value);
+       } else {
+               /* We have status reply. */
+               status_byte = devc->reply[0];
+               /* Constant current */
+               devc->cc_mode[0] = !(status_byte & (1 << 0)); /* Channel one */
+               devc->cc_mode[1] = !(status_byte & (1 << 1)); /* Channel two */
+               /*
+                * Tracking
+                * status_byte & ((1 << 2) | (1 << 3))
+                * 00 independent 01 series 11 parallel
+                */
+               devc->beep_enabled = (1 << 4);
+               devc->ocp_enabled = (status_byte & (1 << 5));
+               devc->output_enabled = (status_byte & (1 << 6));
+               /* Velleman LABPS3005 quirk */
+               if (devc->output_enabled)
+                       devc->ovp_enabled = (status_byte & (1 << 7));
+               sr_dbg("Status: 0x%02x", status_byte);
+               sr_spew("Status: CH1: constant %s CH2: constant %s. "
+                       "Tracking would be %s. Device is "
+                       "%s and %s. Buttons are %s. Output is %s "
+                       "and extra byte is %s.",
+                       (status_byte & (1 << 0)) ? "voltage" : "current",
+                       (status_byte & (1 << 1)) ? "voltage" : "current",
+                       (status_byte & (1 << 2)) ? "parallel" : "series",
+                       (status_byte & (1 << 3)) ? "tracking" : "independent",
+                       (status_byte & (1 << 4)) ? "beeping" : "silent",
+                       (status_byte & (1 << 5)) ? "locked" : "unlocked",
+                       (status_byte & (1 << 6)) ? "enabled" : "disabled",
+                       (status_byte & (1 << 7)) ? "true" : "false");
+       }
+
+       devc->reply_pending = FALSE;
+
+       return ret;
+}
+
+static void next_measurement(struct dev_context *devc)
+{
+       switch (devc->target) {
+       case KAXXXXP_CURRENT:
+               devc->target = KAXXXXP_VOLTAGE;
+               break;
+       case KAXXXXP_CURRENT_MAX:
+               devc->target = KAXXXXP_CURRENT;
+               break;
+       case KAXXXXP_VOLTAGE:
+               devc->target = KAXXXXP_STATUS;
+               break;
+       case KAXXXXP_VOLTAGE_MAX:
+               devc->target = KAXXXXP_CURRENT;
+               break;
+       /* Read back what was set. */
+       case KAXXXXP_BEEP:
+       case KAXXXXP_OCP:
+       case KAXXXXP_OVP:
+       case KAXXXXP_OUTPUT:
+               devc->target = KAXXXXP_STATUS;
+               break;
+       case KAXXXXP_STATUS:
+               devc->target = KAXXXXP_CURRENT;
+               break;
+       default:
+               devc->target = KAXXXXP_CURRENT;
+       }
+}
+
+SR_PRIV int korad_kaxxxxp_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog_old analog;
+       int64_t t, elapsed_us;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       serial = sdi->conn;
+
+       if (revents == G_IO_IN) {
+               /* Get the value. */
+               korad_kaxxxxp_get_reply(serial, devc);
+
+               /* Send the value forward. */
+               packet.type = SR_DF_ANALOG_OLD;
+               packet.payload = &analog;
+               analog.channels = sdi->channels;
+               analog.num_samples = 1;
+               if (devc->target == KAXXXXP_CURRENT) {
+                       analog.mq = SR_MQ_CURRENT;
+                       analog.unit = SR_UNIT_AMPERE;
+                       analog.mqflags = 0;
+                       analog.data = &devc->current;
+                       sr_session_send(sdi, &packet);
+               }
+               if (devc->target == KAXXXXP_VOLTAGE) {
+                       analog.mq = SR_MQ_VOLTAGE;
+                       analog.unit = SR_UNIT_VOLT;
+                       analog.mqflags = SR_MQFLAG_DC;
+                       analog.data = &devc->voltage;
+                       sr_session_send(sdi, &packet);
+                       devc->num_samples++;
+               }
+               next_measurement(devc);
+       } else {
+               /* Time out */
+               if (!devc->reply_pending) {
+                       if (korad_kaxxxxp_query_value(serial, devc) < 0)
+                               return TRUE;
+                       devc->req_sent_at = g_get_monotonic_time();
+                       devc->reply_pending = TRUE;
+               }
+       }
+
+       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       if (devc->limit_msec) {
+               t = (g_get_monotonic_time() - devc->starttime) / 1000;
+               if (t > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached.");
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
+       }
+
+       /* Request next packet, if required. */
+       if (sdi->status == SR_ST_ACTIVE) {
+               if (devc->reply_pending) {
+                       elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
+                       if (elapsed_us > (REQ_TIMEOUT_MS * 1000))
+                               devc->reply_pending = FALSE;
+                       return TRUE;
+               }
+
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/korad-kaxxxxp/protocol.h b/src/hardware/korad-kaxxxxp/protocol.h
new file mode 100644 (file)
index 0000000..1a9dfe3
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
+ *
+ * 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/>.
+ */
+
+/**
+ * @file
+ * Korad KAxxxxP power supply driver
+ * @internal
+ */
+
+#ifndef LIBSIGROK_HARDWARE_KORAD_KAXXXXP_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_KORAD_KAXXXXP_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+#include <libsigrok/libsigrok.h>
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "korad-kaxxxxp"
+
+#define KAXXXXP_POLL_INTERVAL_MS 80
+
+enum {
+       VELLEMAN_LABPS_3005D,
+       /* Support for future devices with this protocol. */
+};
+
+/* Information on single model */
+struct korad_kaxxxxp_model {
+       int model_id; /**< Model info */
+       const char *vendor; /**< Vendor name */
+       const char *name; /**< Model name */
+       const char *id; /**< Model ID, as delivered by interface */
+       int channels; /**< Number of channels */
+       double voltage[3]; /**< Min, max, step */
+       double current[3]; /**< Min, max, step */
+};
+
+/* Reply targets */
+enum {
+       KAXXXXP_CURRENT,
+       KAXXXXP_CURRENT_MAX,
+       KAXXXXP_VOLTAGE,
+       KAXXXXP_VOLTAGE_MAX,
+       KAXXXXP_STATUS,
+       KAXXXXP_OUTPUT,
+       KAXXXXP_BEEP,
+       KAXXXXP_OCP,
+       KAXXXXP_OVP,
+       KAXXXXP_SAVE,
+       KAXXXXP_RECALL,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Model-specific information */
+       const struct korad_kaxxxxp_model *model; /**< Model information. */
+
+       /* Acquisition settings */
+       uint64_t limit_samples;
+       uint64_t limit_msec;
+       uint64_t num_samples;
+       int64_t starttime;
+       int64_t req_sent_at;
+       gboolean reply_pending;
+
+       void *cb_data;
+
+       /* Operational state */
+       float current;          /**< Last current value [A] read from device. */
+       float current_max;      /**< Output current set. */
+       float voltage;          /**< Last voltage value [V] read from device. */
+       float voltage_max;      /**< Output voltage set. */
+       gboolean cc_mode[2];    /**< Device is in CC mode (otherwise CV). */
+
+       gboolean output_enabled; /**< Is the output enabled? */
+       gboolean beep_enabled;   /**< Enable beeper. */
+       gboolean ocp_enabled;    /**< Output current protection enabled. */
+       gboolean ovp_enabled;    /**< Output voltage protection enabled. */
+
+       /* Temporary state across callbacks */
+       int target;              /**< What reply to expect. */
+       int program;             /**< Program to store or recall. */
+       char reply[6];
+};
+
+SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
+                                       const char *cmd);
+SR_PRIV int korad_kaxxxxp_read_chars(struct sr_serial_dev_inst *serial,
+                                       int count, char *buf);
+SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
+                                       struct dev_context *devc);
+SR_PRIV int korad_kaxxxxp_query_value(struct sr_serial_dev_inst *serial,
+                                       struct dev_context *devc);
+SR_PRIV int korad_kaxxxxp_get_reply(struct sr_serial_dev_inst *serial,
+                                       struct dev_context *devc);
+SR_PRIV int korad_kaxxxxp_get_all_values(struct sr_serial_dev_inst *serial,
+                                       struct dev_context *devc);
+SR_PRIV int korad_kaxxxxp_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/korad-kdxxxxp/api.c b/src/hardware/korad-kdxxxxp/api.c
deleted file mode 100644 (file)
index c499d4b..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
- *
- * 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 <config.h>
-#include "protocol.h"
-
-static const uint32_t drvopts[] = {
-       /* Device class */
-       SR_CONF_POWER_SUPPLY,
-};
-
-static const uint32_t scanopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const uint32_t devopts[] = {
-       /* Device class */
-       SR_CONF_POWER_SUPPLY,
-       /* Acquisition modes. */
-       SR_CONF_CONTINUOUS,
-       SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
-       SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
-       /* Device configuration */
-       SR_CONF_VOLTAGE | SR_CONF_GET,
-       SR_CONF_VOLTAGE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
-       SR_CONF_CURRENT | SR_CONF_GET,
-       SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
-       SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
-       SR_CONF_REGULATION | SR_CONF_GET,
-       SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_GET | SR_CONF_SET,
-       SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED | SR_CONF_GET | SR_CONF_SET,
-};
-
-static const struct korad_kdxxxxp_model models[] = {
-       /* Device enum, vendor, model, ID reply, channels, voltage, current */
-       {VELLEMAN_LABPS_3005D, "Velleman", "LABPS3005D",
-               "VELLEMANLABPS3005DV2.0", 1, {0, 31, 0.01}, {0, 5, 0.001}},
-       {0, NULL, NULL, NULL, 0, {0, 0, 0}, {0, 0, 0}}
-};
-
-SR_PRIV struct sr_dev_driver korad_kdxxxxp_driver_info;
-
-static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(struct sr_dev_driver *di, GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       GSList *devices, *l;
-       struct sr_dev_inst *sdi;
-       struct sr_config *src;
-       const char *conn, *serialcomm;
-       struct sr_serial_dev_inst *serial;
-       char reply[50];
-       int i, model_id;
-       unsigned int len;
-
-       devices = NULL;
-       conn = NULL;
-       serialcomm = NULL;
-       drvc = di->context;
-       drvc->instances = 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;
-               default:
-                       sr_err("Unknown option %d, skipping.", src->key);
-                       break;
-               }
-       }
-
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = "9600/8n1";
-
-       serial = sr_serial_dev_inst_new(conn, serialcomm);
-       if (serial_open(serial, SERIAL_RDWR) != SR_OK)
-               return NULL;
-
-       serial_flush(serial);
-
-       /* Get the device model. */
-       len = 0;
-       for (i = 0; models[i].id; i++) {
-               if (strlen(models[i].id) > len)
-                       len = strlen(models[i].id);
-       }
-       memset(&reply, 0, sizeof(reply));
-       sr_dbg("Want max %d bytes.", len);
-       if ((korad_kdxxxxp_send_cmd(serial, "*IDN?") < 0))
-               return NULL;
-
-       /* i is used here for debug purposes only. */
-       if ((i = korad_kdxxxxp_read_chars(serial, len, reply)) < 0)
-               return NULL;
-       sr_dbg("Received: %d, %s", i, reply);
-       model_id = -1;
-       for (i = 0; models[i].id; i++) {
-               if (!strcmp(models[i].id, reply))
-                       model_id = i;
-       }
-       if (model_id < 0) {
-               sr_err("Unknown model ID '%s' detected, aborting.", reply);
-               return NULL;
-       }
-       sr_dbg("Found: %s %s", models[model_id].vendor, models[model_id].name);
-
-       /* Init device instance, etc. */
-       sdi = g_malloc0(sizeof(struct sr_dev_inst));
-       sdi->status = SR_ST_INACTIVE;
-       sdi->vendor = g_strdup(models[model_id].vendor);
-       sdi->model = g_strdup(models[model_id].name);
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-       sdi->driver = di;
-
-       sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "CH1");
-
-       devc = g_malloc0(sizeof(struct dev_context));
-       devc->model = &models[model_id];
-       devc->reply[5] = 0;
-       devc->req_sent_at = 0;
-       sdi->priv = devc;
-
-       /* Get current status of device. */
-       if (korad_kdxxxxp_get_all_values(serial, devc) < 0)
-               goto exit_err;
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-       serial_close(serial);
-       if (!devices)
-               sr_serial_dev_inst_free(serial);
-
-       return devices;
-
-exit_err:
-       sr_dev_inst_free(sdi);
-       g_free(devc);
-       sr_dbg("Scan failed.");
-
-       return NULL;
-}
-
-static GSList *dev_list(const struct sr_dev_driver *di)
-{
-       return ((struct drv_context *)(di->context))->instances;
-}
-
-static int dev_clear(const struct sr_dev_driver *di)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int cleanup(const struct sr_dev_driver *di)
-{
-       dev_clear(di);
-       return SR_OK;
-}
-
-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;
-
-       (void)cg;
-
-       if (!sdi || !data)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               *data = g_variant_new_uint64(devc->limit_msec);
-               break;
-       case SR_CONF_VOLTAGE:
-               *data = g_variant_new_double(devc->voltage);
-               break;
-       case SR_CONF_VOLTAGE_TARGET:
-               *data = g_variant_new_double(devc->voltage_max);
-               break;
-       case SR_CONF_CURRENT:
-               *data = g_variant_new_double(devc->current);
-               break;
-       case SR_CONF_CURRENT_LIMIT:
-               *data = g_variant_new_double(devc->current_max);
-               break;
-       case SR_CONF_ENABLED:
-               *data = g_variant_new_boolean(devc->output_enabled);
-               break;
-       case SR_CONF_REGULATION:
-               /* Dual channel not supported. */
-               *data = g_variant_new_string((devc->cc_mode[0]) ? "CC" : "CV");
-               break;
-       case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
-               *data = g_variant_new_boolean(devc->ocp_enabled);
-               break;
-       case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
-               *data = g_variant_new_boolean(devc->ovp_enabled);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-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;
-       double dval;
-       gboolean bval;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       switch (key) {
-       case SR_CONF_LIMIT_MSEC:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_msec = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_samples = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_VOLTAGE_TARGET:
-               dval = g_variant_get_double(data);
-               if (dval < devc->model->voltage[0] || dval > devc->model->voltage[1])
-                       return SR_ERR_ARG;
-               devc->voltage_max = dval;
-               devc->target = KDXXXXP_VOLTAGE_MAX;
-               if (korad_kdxxxxp_set_value(sdi->conn, devc) < 0)
-                       return SR_ERR;
-               break;
-       case SR_CONF_CURRENT_LIMIT:
-               dval = g_variant_get_double(data);
-               if (dval < devc->model->current[0] || dval > devc->model->current[1])
-                       return SR_ERR_ARG;
-               devc->current_max = dval;
-               devc->target = KDXXXXP_CURRENT_MAX;
-               if (korad_kdxxxxp_set_value(sdi->conn, devc) < 0)
-                       return SR_ERR;
-               break;
-       case SR_CONF_ENABLED:
-               bval = g_variant_get_boolean(data);
-               /* Set always so it is possible turn off with sigrok-cli. */
-               devc->output_enabled = bval;
-               devc->target = KDXXXXP_OUTPUT;
-               if (korad_kdxxxxp_set_value(sdi->conn, devc) < 0)
-                       return SR_ERR;
-               break;
-       case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
-               bval = g_variant_get_boolean(data);
-               devc->ocp_enabled = bval;
-               devc->target = KDXXXXP_OCP;
-               if (korad_kdxxxxp_set_value(sdi->conn, devc) < 0)
-                       return SR_ERR;
-               break;
-       case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
-               bval = g_variant_get_boolean(data);
-               devc->ovp_enabled = bval;
-               devc->target = KDXXXXP_OVP;
-               if (korad_kdxxxxp_set_value(sdi->conn, devc) < 0)
-                       return SR_ERR;
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-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;
-       GVariant *gvar;
-       GVariantBuilder gvb;
-       double dval;
-       int idx;
-
-       (void)cg;
-
-       /* Always available (with or without sdi). */
-       if (key == SR_CONF_SCAN_OPTIONS) {
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
-                       scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
-               return SR_OK;
-       }
-
-       /* Return drvopts without sdi (and devopts with sdi, see below). */
-       if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
-                       drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
-               return SR_OK;
-       }
-
-       /* Every other key needs an sdi. */
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
-                       devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
-               break;
-       case SR_CONF_VOLTAGE_TARGET:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               /* Min, max, step. */
-               for (idx = 0; idx < 3; idx++) {
-                       dval = devc->model->voltage[idx];
-                       gvar = g_variant_new_double(dval);
-                       g_variant_builder_add_value(&gvb, gvar);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_CURRENT_LIMIT:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               /* Min, max, step. */
-               for (idx = 0; idx < 3; idx++) {
-                       dval = devc->model->current[idx];
-                       gvar = g_variant_new_double(dval);
-                       g_variant_builder_add_value(&gvb, gvar);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       devc->starttime = g_get_monotonic_time();
-       devc->num_samples = 0;
-       devc->reply_pending = FALSE;
-       devc->req_sent_at = 0;
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN,
-                       KDXXXXP_POLL_INTERVAL_MS,
-                       korad_kdxxxxp_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       return std_serial_dev_acquisition_stop(sdi, cb_data,
-               std_serial_dev_close, sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver korad_kdxxxxp_driver_info = {
-       .name = "korad-kdxxxxp",
-       .longname = "Korad KDxxxxP",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = 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 = dev_acquisition_stop,
-       .context = NULL,
-};
diff --git a/src/hardware/korad-kdxxxxp/protocol.c b/src/hardware/korad-kdxxxxp/protocol.c
deleted file mode 100644 (file)
index bec63b4..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
- *
- * 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 <config.h>
-#include "protocol.h"
-
-#define REQ_TIMEOUT_MS 500
-#define DEVICE_PROCESSING_TIME_MS 80
-
-SR_PRIV int korad_kdxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
-                               const char *cmd)
-{
-       int ret;
-
-       sr_dbg("Sending '%s'.", cmd);
-       if ((ret = serial_write_blocking(serial, cmd, strlen(cmd), 0)) < 0) {
-               sr_err("Error sending command: %d.", ret);
-               return ret;
-       }
-
-       return ret;
-}
-
-SR_PRIV int korad_kdxxxxp_read_chars(struct sr_serial_dev_inst *serial,
-                               int count, char *buf)
-{
-       int ret, received, turns;
-
-       received = 0;
-       turns = 0;
-
-       do {
-               if ((ret = serial_read_blocking(serial, buf + received,
-                               count - received,
-                               serial_timeout(serial, count))) < 0) {
-                       sr_err("Error %d reading %d bytes from device.",
-                              ret, count);
-                       return ret;
-               }
-               received += ret;
-               turns++;
-       } while ((received < count) && (turns < 100));
-
-       buf[count] = 0;
-
-       sr_spew("Received: '%s'.", buf);
-
-       return ret;
-}
-
-static void give_device_time_to_process(struct dev_context *devc)
-{
-       int64_t sleeping_time;
-
-       sleeping_time = devc->req_sent_at + (DEVICE_PROCESSING_TIME_MS * 1000);
-       sleeping_time -= g_get_monotonic_time();
-
-       if (sleeping_time > 0) {
-               g_usleep(sleeping_time);
-               sr_spew("Sleeping for processing %" PRIi64 " usec", sleeping_time);
-       }
-}
-
-SR_PRIV int korad_kdxxxxp_set_value(struct sr_serial_dev_inst *serial,
-                               struct dev_context *devc)
-{
-       char msg[21];
-       const char *cmd;
-       float value;
-       int ret;
-
-       give_device_time_to_process(devc);
-
-       msg[20] = 0;
-       switch(devc->target){
-       case KDXXXXP_CURRENT:
-       case KDXXXXP_VOLTAGE:
-       case KDXXXXP_STATUS:
-               sr_err("Can't set measurable parameter.");
-               return SR_ERR;
-       case KDXXXXP_CURRENT_MAX:
-               cmd = "ISET1:%05.3f";
-               value = devc->current_max;
-               break;
-       case KDXXXXP_VOLTAGE_MAX:
-               cmd = "VSET1:%05.2f";
-               value = devc->voltage_max;
-               break;
-       case KDXXXXP_OUTPUT:
-               cmd = "OUT%01.0f";
-               value = (devc->output_enabled) ? 1 : 0;
-               break;
-       case KDXXXXP_BEEP:
-               cmd = "BEEP%01.0f";
-               value = (devc->beep_enabled) ? 1 : 0;
-               break;
-       case KDXXXXP_OCP:
-               cmd = "OCP%01.0f";
-               value = (devc->ocp_enabled) ? 1 : 0;
-               break;
-       case KDXXXXP_OVP:
-               cmd = "OVP%01.0f";
-               value = (devc->ovp_enabled) ? 1 : 0;
-               break;
-       case KDXXXXP_SAVE:
-               cmd = "SAV%01.0f";
-               if (devc->program < 1 || devc->program > 5) {
-                       sr_err("Only programs 1-5 supported and %d isn't "
-                              "between them.", devc->program);
-                       return SR_ERR;
-               }
-               value = devc->program;
-               break;
-       case KDXXXXP_RECALL:
-               cmd = "RCL%01.0f";
-               if (devc->program < 1 || devc->program > 5) {
-                       sr_err("Only programs 1-5 supported and %d isn't "
-                              "between them.", devc->program);
-                       return SR_ERR;
-               }
-               value = devc->program;
-               break;
-       default:
-               sr_err("Don't know how to set %d.", devc->target);
-               return SR_ERR;
-       }
-
-       if (cmd)
-               snprintf(msg, 20, cmd, value);
-
-       ret = korad_kdxxxxp_send_cmd(serial, msg);
-       devc->req_sent_at = g_get_monotonic_time();
-       devc->reply_pending = FALSE;
-
-       return ret;
-}
-
-SR_PRIV int korad_kdxxxxp_query_value(struct sr_serial_dev_inst *serial,
-                               struct dev_context *devc)
-{
-       int ret;
-
-       give_device_time_to_process(devc);
-
-       switch(devc->target){
-       case KDXXXXP_CURRENT:
-               /* Read current from device. */
-               ret = korad_kdxxxxp_send_cmd(serial, "IOUT1?");
-               break;
-       case KDXXXXP_CURRENT_MAX:
-               /* Read set current from device. */
-               ret = korad_kdxxxxp_send_cmd(serial, "ISET1?");
-               break;
-       case KDXXXXP_VOLTAGE:
-               /* Read voltage from device. */
-               ret = korad_kdxxxxp_send_cmd(serial, "VOUT1?");
-               break;
-       case KDXXXXP_VOLTAGE_MAX:
-               /* Read set voltage from device. */
-               ret = korad_kdxxxxp_send_cmd(serial, "VSET1?");
-               break;
-       case KDXXXXP_STATUS:
-       case KDXXXXP_OUTPUT:
-               /* Read status from device. */
-               ret = korad_kdxxxxp_send_cmd(serial, "STATUS?");
-               break;
-       default:
-               sr_err("Don't know how to query %d.", devc->target);
-               return SR_ERR;
-       }
-
-       devc->req_sent_at = g_get_monotonic_time();
-       devc->reply_pending = TRUE;
-
-       return ret;
-}
-
-SR_PRIV int korad_kdxxxxp_get_all_values(struct sr_serial_dev_inst *serial,
-                               struct dev_context *devc)
-{
-       int ret;
-
-       for (devc->target = KDXXXXP_CURRENT;
-                       devc->target <= KDXXXXP_STATUS; devc->target++) {
-               if ((ret = korad_kdxxxxp_query_value(serial, devc)) < 0)
-                       return ret;
-               if ((ret = korad_kdxxxxp_get_reply(serial, devc)) < 0)
-                       return ret;
-       }
-
-       return ret;
-}
-
-SR_PRIV int korad_kdxxxxp_get_reply(struct sr_serial_dev_inst *serial,
-                               struct dev_context *devc)
-{
-       double value;
-       int count, ret, i;
-       float *target;
-       char status_byte;
-
-       target = NULL;
-       count = 5;
-
-       switch (devc->target) {
-       case KDXXXXP_CURRENT:
-               /* Read current from device. */
-               target = &(devc->current);
-               break;
-       case KDXXXXP_CURRENT_MAX:
-               /* Read set current from device. */
-               target = &(devc->current_max);
-               break;
-       case KDXXXXP_VOLTAGE:
-               /* Read voltage from device. */
-               target = &(devc->voltage);
-               break;
-       case KDXXXXP_VOLTAGE_MAX:
-               /* Read set voltage from device. */
-               target = &(devc->voltage_max);
-               break;
-       case KDXXXXP_STATUS:
-       case KDXXXXP_OUTPUT:
-               /* Read status from device. */
-               count = 1;
-               break;
-       default:
-               sr_err("Don't know where to put repply %d.", devc->target);
-       }
-
-       if ((ret = korad_kdxxxxp_read_chars(serial, count, devc->reply)) < 0)
-               return ret;
-
-       devc->reply[count] = 0;
-
-       if (target) {
-               /* Handle the strange 'M'. */
-               if (devc->reply[0] == 'M') {
-                       for (i = 1; i < count; i++)
-                               devc->reply[i - 1] = devc->reply[i];
-                       /* Get the last character. */
-                       if ((i = korad_kdxxxxp_read_chars(serial, 1,
-                                               &(devc->reply[count]))) < 0)
-                               return i;
-               }
-               value = g_ascii_strtod(devc->reply, NULL);
-               *target = (float)value;
-               sr_dbg("value: %f",value);
-       } else {
-               /* We have status reply. */
-               status_byte = devc->reply[0];
-               /* Constant current */
-               devc->cc_mode[0] = !(status_byte & (1 << 0)); /* Channel one */
-               devc->cc_mode[1] = !(status_byte & (1 << 1)); /* Channel two */
-               /*
-                * Tracking
-                * status_byte & ((1 << 2) | (1 << 3))
-                * 00 independent 01 series 11 parallel
-                */
-               devc->beep_enabled = (1 << 4);
-               devc->ocp_enabled = (status_byte & (1 << 5));
-               devc->output_enabled = (status_byte & (1 << 6));
-               /* Velleman LABPS3005 quirk */
-               if (devc->output_enabled)
-                       devc->ovp_enabled = (status_byte & (1 << 7));
-               sr_dbg("Status: 0x%02x", status_byte);
-               sr_spew("Status: CH1: constant %s CH2: constant %s. "
-                       "Tracking would be %s. Device is "
-                       "%s and %s. Buttons are %s. Output is %s "
-                       "and extra byte is %s.",
-                       (status_byte & (1 << 0)) ? "voltage" : "current",
-                       (status_byte & (1 << 1)) ? "voltage" : "current",
-                       (status_byte & (1 << 2)) ? "parallel" : "series",
-                       (status_byte & (1 << 3)) ? "tracking" : "independent",
-                       (status_byte & (1 << 4)) ? "beeping" : "silent",
-                       (status_byte & (1 << 5)) ? "locked" : "unlocked",
-                       (status_byte & (1 << 6)) ? "enabled" : "disabled",
-                       (status_byte & (1 << 7)) ? "true" : "false");
-       }
-
-       devc->reply_pending = FALSE;
-
-       return ret;
-}
-
-static void next_measurement(struct dev_context *devc)
-{
-       switch (devc->target) {
-       case KDXXXXP_CURRENT:
-               devc->target = KDXXXXP_VOLTAGE;
-               break;
-       case KDXXXXP_CURRENT_MAX:
-               devc->target = KDXXXXP_CURRENT;
-               break;
-       case KDXXXXP_VOLTAGE:
-               devc->target = KDXXXXP_STATUS;
-               break;
-       case KDXXXXP_VOLTAGE_MAX:
-               devc->target = KDXXXXP_CURRENT;
-               break;
-       /* Read back what was set. */
-       case KDXXXXP_BEEP:
-       case KDXXXXP_OCP:
-       case KDXXXXP_OVP:
-       case KDXXXXP_OUTPUT:
-               devc->target = KDXXXXP_STATUS;
-               break;
-       case KDXXXXP_STATUS:
-               devc->target = KDXXXXP_CURRENT;
-               break;
-       default:
-               devc->target = KDXXXXP_CURRENT;
-       }
-}
-
-SR_PRIV int korad_kdxxxxp_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog_old analog;
-       int64_t t, elapsed_us;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       serial = sdi->conn;
-
-       if (revents == G_IO_IN) {
-               /* Get the value. */
-               korad_kdxxxxp_get_reply(serial, devc);
-
-               /* Send the value forward. */
-               packet.type = SR_DF_ANALOG_OLD;
-               packet.payload = &analog;
-               analog.channels = sdi->channels;
-               analog.num_samples = 1;
-               if (devc->target == KDXXXXP_CURRENT) {
-                       analog.mq = SR_MQ_CURRENT;
-                       analog.unit = SR_UNIT_AMPERE;
-                       analog.mqflags = 0;
-                       analog.data = &devc->current;
-                       sr_session_send(sdi, &packet);
-               }
-               if (devc->target == KDXXXXP_VOLTAGE) {
-                       analog.mq = SR_MQ_VOLTAGE;
-                       analog.unit = SR_UNIT_VOLT;
-                       analog.mqflags = SR_MQFLAG_DC;
-                       analog.data = &devc->voltage;
-                       sr_session_send(sdi, &packet);
-                       devc->num_samples++;
-               }
-               next_measurement(devc);
-       } else {
-               /* Time out */
-               if (!devc->reply_pending) {
-                       if (korad_kdxxxxp_query_value(serial, devc) < 0)
-                               return TRUE;
-                       devc->req_sent_at = g_get_monotonic_time();
-                       devc->reply_pending = TRUE;
-               }
-       }
-
-       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       }
-
-       if (devc->limit_msec) {
-               t = (g_get_monotonic_time() - devc->starttime) / 1000;
-               if (t > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached.");
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       return TRUE;
-               }
-       }
-
-       /* Request next packet, if required. */
-       if (sdi->status == SR_ST_ACTIVE) {
-               if (devc->reply_pending) {
-                       elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
-                       if (elapsed_us > (REQ_TIMEOUT_MS * 1000))
-                               devc->reply_pending = FALSE;
-                       return TRUE;
-               }
-
-       }
-
-       return TRUE;
-}
diff --git a/src/hardware/korad-kdxxxxp/protocol.h b/src/hardware/korad-kdxxxxp/protocol.h
deleted file mode 100644 (file)
index a76b28b..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
- *
- * 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/>.
- */
-
-/**
- * @file
- * Korad KDxxxxP power supply driver
- * @internal
- */
-
-#ifndef LIBSIGROK_HARDWARE_KORAD_KDXXXXP_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_KORAD_KDXXXXP_PROTOCOL_H
-
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <libsigrok/libsigrok.h>
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "korad-kdxxxxp"
-
-#define KDXXXXP_POLL_INTERVAL_MS 80
-
-enum {
-       VELLEMAN_LABPS_3005D,
-       /* Support for future devices with this protocol. */
-};
-
-/* Information on single model */
-struct korad_kdxxxxp_model {
-       int model_id; /**< Model info */
-       const char *vendor; /**< Vendor name */
-       const char *name; /**< Model name */
-       const char *id; /**< Model ID, as delivered by interface */
-       int channels; /**< Number of channels */
-       double voltage[3]; /**< Min, max, step */
-       double current[3]; /**< Min, max, step */
-};
-
-/* Reply targets */
-enum {
-       KDXXXXP_CURRENT,
-       KDXXXXP_CURRENT_MAX,
-       KDXXXXP_VOLTAGE,
-       KDXXXXP_VOLTAGE_MAX,
-       KDXXXXP_STATUS,
-       KDXXXXP_OUTPUT,
-       KDXXXXP_BEEP,
-       KDXXXXP_OCP,
-       KDXXXXP_OVP,
-       KDXXXXP_SAVE,
-       KDXXXXP_RECALL,
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Model-specific information */
-       const struct korad_kdxxxxp_model *model; /**< Model information. */
-
-       /* Acquisition settings */
-       uint64_t limit_samples;
-       uint64_t limit_msec;
-       uint64_t num_samples;
-       int64_t starttime;
-       int64_t req_sent_at;
-       gboolean reply_pending;
-
-       void *cb_data;
-
-       /* Operational state */
-       float current;          /**< Last current value [A] read from device. */
-       float current_max;      /**< Output current set. */
-       float voltage;          /**< Last voltage value [V] read from device. */
-       float voltage_max;      /**< Output voltage set. */
-       gboolean cc_mode[2];    /**< Device is in CC mode (otherwise CV). */
-
-       gboolean output_enabled; /**< Is the output enabled? */
-       gboolean beep_enabled;   /**< Enable beeper. */
-       gboolean ocp_enabled;    /**< Output current protection enabled. */
-       gboolean ovp_enabled;    /**< Output voltage protection enabled. */
-
-       /* Temporary state across callbacks */
-       int target;              /**< What reply to expect. */
-       int program;             /**< Program to store or recall. */
-       char reply[6];
-};
-
-SR_PRIV int korad_kdxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
-                                       const char *cmd);
-SR_PRIV int korad_kdxxxxp_read_chars(struct sr_serial_dev_inst *serial,
-                                       int count, char *buf);
-SR_PRIV int korad_kdxxxxp_set_value(struct sr_serial_dev_inst *serial,
-                                       struct dev_context *devc);
-SR_PRIV int korad_kdxxxxp_query_value(struct sr_serial_dev_inst *serial,
-                                       struct dev_context *devc);
-SR_PRIV int korad_kdxxxxp_get_reply(struct sr_serial_dev_inst *serial,
-                                       struct dev_context *devc);
-SR_PRIV int korad_kdxxxxp_get_all_values(struct sr_serial_dev_inst *serial,
-                                       struct dev_context *devc);
-SR_PRIV int korad_kdxxxxp_receive_data(int fd, int revents, void *cb_data);
-
-#endif