]> sigrok.org Git - libsigrok.git/commitdiff
hameg-hmo: Add support for SR_CONF_LOGIC_THRESHOLD/_CUSTOM.
authorGuido Trentalancia <redacted>
Fri, 16 Nov 2018 17:43:55 +0000 (18:43 +0100)
committerUwe Hermann <redacted>
Thu, 25 Jul 2019 22:11:07 +0000 (00:11 +0200)
Update the Hameg/Rohde&Schwarz HMO driver (hameg-hmo) so that it
is possible to configure the logic threshold for digital signals.

The user can get or set the logic threshold configuration using
the channel group POD0 (and/or POD1 where available), for example:

sigrok-cli --driver hameg-hmo --get logic_threshold -g POD0
sigrok-cli --driver hameg-hmo --config logic_threshold=TTL --set -g POD0

sigrok-cli --driver hameg-hmo --get logic_threshold_custom -g POD0
sigrok-cli --driver hameg-hmo --config logic_threshold_custom=0.7 --set -g POD0

include/libsigrok/libsigrok.h
src/hardware/hameg-hmo/api.c
src/hardware/hameg-hmo/protocol.c
src/hardware/hameg-hmo/protocol.h
src/hwdriver.c
src/scpi.h

index bb0b4fe7666d8340b030ad6b8c8cce37b02ab0fa..a60e53bd17f995f7059a291919645feaaa7f9881 100644 (file)
@@ -830,6 +830,12 @@ enum sr_configkey {
        /** Logic low-high threshold range. */
        SR_CONF_VOLTAGE_THRESHOLD,
 
+       /** Logic threshold: predefined levels (TTL, ECL, CMOS, etc). */
+       SR_CONF_LOGIC_THRESHOLD,
+
+       /** Logic threshold: custom numerical value. */
+       SR_CONF_LOGIC_THRESHOLD_CUSTOM,
+
        /** The device supports using an external clock. */
        SR_CONF_EXTERNAL_CLOCK,
 
index 56b95c38db80a06d7d7a2f88fd0cd0798ba25193..0070b61569800e3132bbc8ae4e816eb1dac13696 100644 (file)
@@ -2,6 +2,7 @@
  * This file is part of the libsigrok project.
  *
  * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho@gmail.com>
+ * Copyright (C) 2018 Guido Trentalancia <guido@trentalancia.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
@@ -214,6 +215,30 @@ static int config_get(uint32_t key, GVariant **data,
        case SR_CONF_SAMPLERATE:
                *data = g_variant_new_uint64(state->sample_rate);
                break;
+       case SR_CONF_LOGIC_THRESHOLD:
+               if (!cg)
+                       return SR_ERR_CHANNEL_GROUP;
+               if (cg_type != CG_DIGITAL)
+                       return SR_ERR_NA;
+               if (!model)
+                       return SR_ERR_ARG;
+               if ((idx = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
+                       return SR_ERR_ARG;
+               *data = g_variant_new_string((*model->logic_threshold)[state->digital_pods[idx].threshold]);
+               break;
+       case SR_CONF_LOGIC_THRESHOLD_CUSTOM:
+               if (!cg)
+                       return SR_ERR_CHANNEL_GROUP;
+               if (cg_type != CG_DIGITAL)
+                       return SR_ERR_NA;
+               if (!model)
+                       return SR_ERR_ARG;
+               if ((idx = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
+                       return SR_ERR_ARG;
+               if (strcmp("USER2", (*model->logic_threshold)[state->digital_pods[idx].threshold]))
+                       return SR_ERR_NA;
+               *data = g_variant_new_double(state->digital_pods[idx].user_threshold);
+               break;
        default:
                return SR_ERR_NA;
        }
@@ -332,6 +357,54 @@ static int config_set(uint32_t key, GVariant *data,
                        return SR_ERR;
                ret = SR_OK;
                break;
+       case SR_CONF_LOGIC_THRESHOLD:
+               if (!cg)
+                       return SR_ERR_CHANNEL_GROUP;
+               if (cg_type != CG_DIGITAL)
+                       return SR_ERR_NA;
+               if (!model)
+                       return SR_ERR_ARG;
+               if ((idx = std_str_idx(data, *model->logic_threshold, model->num_logic_threshold)) < 0)
+                       return SR_ERR_ARG;
+               if ((j = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
+                       return SR_ERR_ARG;
+               g_snprintf(command, sizeof(command),
+                          (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
+                          j + 1, (*model->logic_threshold)[idx]);
+               if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+                   sr_scpi_get_opc(sdi->conn) != SR_OK)
+                       return SR_ERR;
+               state->digital_pods[j].threshold = idx;
+               ret = SR_OK;
+               break;
+       case SR_CONF_LOGIC_THRESHOLD_CUSTOM:
+               if (!cg)
+                       return SR_ERR_CHANNEL_GROUP;
+               if (cg_type != CG_DIGITAL)
+                       return SR_ERR_NA;
+               if (!model)
+                       return SR_ERR_ARG;
+               if ((j = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
+                       return SR_ERR_ARG;
+               tmp_d = g_variant_get_double(data);
+               if (tmp_d < -2.0 || tmp_d > 8.0)
+                       return SR_ERR;
+               g_ascii_formatd(float_str, sizeof(float_str), "%E", tmp_d);
+               g_snprintf(command, sizeof(command),
+                          (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
+                          j + 1, 2, float_str); // USER2 for custom logic_threshold setting
+               if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+                   sr_scpi_get_opc(sdi->conn) != SR_OK)
+                       return SR_ERR;
+               g_snprintf(command, sizeof(command),
+                          (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
+                          j + 1, "USER2");
+               if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+                   sr_scpi_get_opc(sdi->conn) != SR_OK)
+                       return SR_ERR;
+               state->digital_pods[j].user_threshold = tmp_d;
+               ret = SR_OK;
+               break;
        default:
                ret = SR_ERR_NA;
                break;
@@ -373,6 +446,8 @@ static int config_list(uint32_t key, GVariant **data,
                                *data = std_gvar_array_u32(ARRAY_AND_SIZE(drvopts));
                } else if (cg_type == CG_ANALOG) {
                        *data = std_gvar_array_u32(*model->devopts_cg_analog, model->num_devopts_cg_analog);
+               } else if (cg_type == CG_DIGITAL) {
+                       *data = std_gvar_array_u32(*model->devopts_cg_digital, model->num_devopts_cg_digital);
                } else {
                        *data = std_gvar_array_u32(NULL, 0);
                }
@@ -406,6 +481,13 @@ static int config_list(uint32_t key, GVariant **data,
                        return SR_ERR_ARG;
                *data = std_gvar_tuple_array(*model->vdivs, model->num_vdivs);
                break;
+       case SR_CONF_LOGIC_THRESHOLD:
+               if (!cg)
+                       return SR_ERR_CHANNEL_GROUP;
+               if (!model)
+                       return SR_ERR_ARG;
+               *data = g_variant_new_strv(*model->logic_threshold, model->num_logic_threshold);
+               break;
        default:
                return SR_ERR_NA;
        }
@@ -568,7 +650,7 @@ static int hmo_setup_channels(const struct sr_dev_inst *sdi)
 
        ret = SR_OK;
        for (i = 0; i < model->digital_pods; i++) {
-               if (state->digital_pods[i] == pod_enabled[i])
+               if (state->digital_pods[i].state == pod_enabled[i])
                        continue;
                g_snprintf(command, sizeof(command),
                           (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_STATE],
@@ -577,7 +659,7 @@ static int hmo_setup_channels(const struct sr_dev_inst *sdi)
                        ret = SR_ERR;
                        break;
                }
-               state->digital_pods[i] = pod_enabled[i];
+               state->digital_pods[i].state = pod_enabled[i];
                setup_changed = TRUE;
        }
        g_free(pod_enabled);
index 41b14d48b71aa5b10fe01cec522b23a5ae6c5333..119f00946a83ff70b664c6214c0d9486a5bb03d3 100644 (file)
@@ -2,6 +2,7 @@
  * This file is part of the libsigrok project.
  *
  * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho@gmail.com>
+ * Copyright (C) 2018 Guido Trentalancia <guido@trentalancia.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
@@ -30,31 +31,35 @@ SR_PRIV void hmo_send_logic_packet(struct sr_dev_inst *sdi,
 SR_PRIV void hmo_cleanup_logic_data(struct dev_context *devc);
 
 static const char *hameg_scpi_dialect[] = {
-       [SCPI_CMD_GET_DIG_DATA]             = ":FORM UINT,8;:POD%d:DATA?",
-       [SCPI_CMD_GET_TIMEBASE]             = ":TIM:SCAL?",
-       [SCPI_CMD_SET_TIMEBASE]             = ":TIM:SCAL %s",
-       [SCPI_CMD_GET_COUPLING]             = ":CHAN%d:COUP?",
-       [SCPI_CMD_SET_COUPLING]             = ":CHAN%d:COUP %s",
-       [SCPI_CMD_GET_SAMPLE_RATE]          = ":ACQ:SRAT?",
-       [SCPI_CMD_GET_SAMPLE_RATE_LIVE]     = ":%s:DATA:POINTS?",
-       [SCPI_CMD_GET_ANALOG_DATA]          = ":FORM:BORD %s;" \
-                                             ":FORM REAL,32;:CHAN%d:DATA?",
-       [SCPI_CMD_GET_VERTICAL_DIV]         = ":CHAN%d:SCAL?",
-       [SCPI_CMD_SET_VERTICAL_DIV]         = ":CHAN%d:SCAL %s",
-       [SCPI_CMD_GET_DIG_POD_STATE]        = ":POD%d:STAT?",
-       [SCPI_CMD_SET_DIG_POD_STATE]        = ":POD%d:STAT %d",
-       [SCPI_CMD_GET_TRIGGER_SLOPE]        = ":TRIG:A:EDGE:SLOP?",
-       [SCPI_CMD_SET_TRIGGER_SLOPE]        = ":TRIG:A:EDGE:SLOP %s",
-       [SCPI_CMD_GET_TRIGGER_SOURCE]       = ":TRIG:A:SOUR?",
-       [SCPI_CMD_SET_TRIGGER_SOURCE]       = ":TRIG:A:SOUR %s",
-       [SCPI_CMD_GET_DIG_CHAN_STATE]       = ":LOG%d:STAT?",
-       [SCPI_CMD_SET_DIG_CHAN_STATE]       = ":LOG%d:STAT %d",
-       [SCPI_CMD_GET_VERTICAL_OFFSET]      = ":CHAN%d:POS?",
-       [SCPI_CMD_GET_HORIZ_TRIGGERPOS]     = ":TIM:POS?",
-       [SCPI_CMD_SET_HORIZ_TRIGGERPOS]     = ":TIM:POS %s",
-       [SCPI_CMD_GET_ANALOG_CHAN_STATE]    = ":CHAN%d:STAT?",
-       [SCPI_CMD_SET_ANALOG_CHAN_STATE]    = ":CHAN%d:STAT %d",
-       [SCPI_CMD_GET_PROBE_UNIT]           = ":PROB%d:SET:ATT:UNIT?",
+       [SCPI_CMD_GET_DIG_DATA]               = ":FORM UINT,8;:POD%d:DATA?",
+       [SCPI_CMD_GET_TIMEBASE]               = ":TIM:SCAL?",
+       [SCPI_CMD_SET_TIMEBASE]               = ":TIM:SCAL %s",
+       [SCPI_CMD_GET_COUPLING]               = ":CHAN%d:COUP?",
+       [SCPI_CMD_SET_COUPLING]               = ":CHAN%d:COUP %s",
+       [SCPI_CMD_GET_SAMPLE_RATE]            = ":ACQ:SRAT?",
+       [SCPI_CMD_GET_SAMPLE_RATE_LIVE]       = ":%s:DATA:POINTS?",
+       [SCPI_CMD_GET_ANALOG_DATA]            = ":FORM:BORD %s;" \
+                                               ":FORM REAL,32;:CHAN%d:DATA?",
+       [SCPI_CMD_GET_VERTICAL_DIV]           = ":CHAN%d:SCAL?",
+       [SCPI_CMD_SET_VERTICAL_DIV]           = ":CHAN%d:SCAL %s",
+       [SCPI_CMD_GET_DIG_POD_STATE]          = ":POD%d:STAT?",
+       [SCPI_CMD_SET_DIG_POD_STATE]          = ":POD%d:STAT %d",
+       [SCPI_CMD_GET_TRIGGER_SLOPE]          = ":TRIG:A:EDGE:SLOP?",
+       [SCPI_CMD_SET_TRIGGER_SLOPE]          = ":TRIG:A:EDGE:SLOP %s",
+       [SCPI_CMD_GET_TRIGGER_SOURCE]         = ":TRIG:A:SOUR?",
+       [SCPI_CMD_SET_TRIGGER_SOURCE]         = ":TRIG:A:SOUR %s",
+       [SCPI_CMD_GET_DIG_CHAN_STATE]         = ":LOG%d:STAT?",
+       [SCPI_CMD_SET_DIG_CHAN_STATE]         = ":LOG%d:STAT %d",
+       [SCPI_CMD_GET_VERTICAL_OFFSET]        = ":CHAN%d:POS?",
+       [SCPI_CMD_GET_HORIZ_TRIGGERPOS]       = ":TIM:POS?",
+       [SCPI_CMD_SET_HORIZ_TRIGGERPOS]       = ":TIM:POS %s",
+       [SCPI_CMD_GET_ANALOG_CHAN_STATE]      = ":CHAN%d:STAT?",
+       [SCPI_CMD_SET_ANALOG_CHAN_STATE]      = ":CHAN%d:STAT %d",
+       [SCPI_CMD_GET_PROBE_UNIT]             = ":PROB%d:SET:ATT:UNIT?",
+       [SCPI_CMD_GET_DIG_POD_THRESHOLD]      = ":POD%d:THR?",
+       [SCPI_CMD_SET_DIG_POD_THRESHOLD]      = ":POD%d:THR %s",
+       [SCPI_CMD_GET_DIG_POD_USER_THRESHOLD] = ":POD%d:THR:UDL%d?",
+       [SCPI_CMD_SET_DIG_POD_USER_THRESHOLD] = ":POD%d:THR:UDL%d %s",
 };
 
 static const uint32_t devopts[] = {
@@ -75,6 +80,11 @@ static const uint32_t devopts_cg_analog[] = {
        SR_CONF_COUPLING | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
 };
 
+static const uint32_t devopts_cg_digital[] = {
+       SR_CONF_LOGIC_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+       SR_CONF_LOGIC_THRESHOLD_CUSTOM | SR_CONF_GET | SR_CONF_SET,
+};
+
 static const char *coupling_options[] = {
        "AC",  // AC with 50 Ohm termination (152x, 202x, 30xx, 1202)
        "ACL", // AC with 1 MOhm termination
@@ -89,6 +99,15 @@ static const char *scope_trigger_slopes[] = {
        "EITH",
 };
 
+/* Predefined logic thresholds. */
+static const char *logic_threshold[] = {
+       "TTL",
+       "ECL",
+       "CMOS",
+       "USER1",
+       "USER2", // overwritten by logic_threshold_custom, use USER1 for permanent setting
+};
+
 /* HMO compact2 */
 static const char *an2_dig8_trigger_sources[] = {
        "CH1", "CH2",
@@ -204,9 +223,15 @@ static const struct scope_config scope_models[] = {
                .devopts_cg_analog = &devopts_cg_analog,
                .num_devopts_cg_analog = ARRAY_SIZE(devopts_cg_analog),
 
+               .devopts_cg_digital = &devopts_cg_digital,
+               .num_devopts_cg_digital = ARRAY_SIZE(devopts_cg_digital),
+
                .coupling_options = &coupling_options,
                .num_coupling_options = ARRAY_SIZE(coupling_options),
 
+               .logic_threshold = &logic_threshold,
+               .num_logic_threshold = ARRAY_SIZE(logic_threshold),
+
                .trigger_sources = &an2_dig8_trigger_sources,
                .num_trigger_sources = ARRAY_SIZE(an2_dig8_trigger_sources),
 
@@ -240,9 +265,15 @@ static const struct scope_config scope_models[] = {
                .devopts_cg_analog = &devopts_cg_analog,
                .num_devopts_cg_analog = ARRAY_SIZE(devopts_cg_analog),
 
+               .devopts_cg_digital = &devopts_cg_digital,
+               .num_devopts_cg_digital = ARRAY_SIZE(devopts_cg_digital),
+
                .coupling_options = &coupling_options,
                .num_coupling_options = ARRAY_SIZE(coupling_options),
 
+               .logic_threshold = &logic_threshold,
+               .num_logic_threshold = ARRAY_SIZE(logic_threshold),
+
                .trigger_sources = &an2_dig16_trigger_sources,
                .num_trigger_sources = ARRAY_SIZE(an2_dig16_trigger_sources),
 
@@ -275,9 +306,15 @@ static const struct scope_config scope_models[] = {
                .devopts_cg_analog = &devopts_cg_analog,
                .num_devopts_cg_analog = ARRAY_SIZE(devopts_cg_analog),
 
+               .devopts_cg_digital = &devopts_cg_digital,
+               .num_devopts_cg_digital = ARRAY_SIZE(devopts_cg_digital),
+
                .coupling_options = &coupling_options,
                .num_coupling_options = ARRAY_SIZE(coupling_options),
 
+               .logic_threshold = &logic_threshold,
+               .num_logic_threshold = ARRAY_SIZE(logic_threshold),
+
                .trigger_sources = &an4_dig8_trigger_sources,
                .num_trigger_sources = ARRAY_SIZE(an4_dig8_trigger_sources),
 
@@ -310,9 +347,15 @@ static const struct scope_config scope_models[] = {
                .devopts_cg_analog = &devopts_cg_analog,
                .num_devopts_cg_analog = ARRAY_SIZE(devopts_cg_analog),
 
+               .devopts_cg_digital = &devopts_cg_digital,
+               .num_devopts_cg_digital = ARRAY_SIZE(devopts_cg_digital),
+
                .coupling_options = &coupling_options,
                .num_coupling_options = ARRAY_SIZE(coupling_options),
 
+               .logic_threshold = &logic_threshold,
+               .num_logic_threshold = ARRAY_SIZE(logic_threshold),
+
                .trigger_sources = &an4_dig16_trigger_sources,
                .num_trigger_sources = ARRAY_SIZE(an4_dig16_trigger_sources),
 
@@ -353,8 +396,14 @@ static void scope_state_dump(const struct scope_config *config,
        }
 
        for (i = 0; i < config->digital_pods; i++) {
-               sr_info("State of digital POD %d -> %s", i,
-                       state->digital_pods[i] ? "On" : "Off");
+               if (strncmp("USER", (*config->logic_threshold)[state->digital_pods[i].threshold], 4))
+                       sr_info("State of digital POD %d -> %s : %s (threshold)", i,
+                               state->digital_pods[i].state ? "On" : "Off",
+                               (*config->logic_threshold)[state->digital_pods[i].threshold]);
+               else // user-defined or custom logic threshold
+                       sr_info("State of digital POD %d -> %s : %E (threshold)", i,
+                               state->digital_pods[i].state ? "On" : "Off",
+                               state->digital_pods[i].user_threshold);
        }
 
        tmp = sr_period_string((*config->timebases)[state->timebase][0],
@@ -518,6 +567,8 @@ static int digital_channel_state_get(struct sr_dev_inst *sdi,
                                     struct scope_state *state)
 {
        unsigned int i;
+       int result = SR_ERR;
+       static char *logic_threshold_short[] = {};
        char command[MAX_COMMAND_SIZE];
        struct sr_channel *ch;
        struct sr_scpi_dev_inst *scpi = sdi->conn;
@@ -536,17 +587,67 @@ static int digital_channel_state_get(struct sr_dev_inst *sdi,
                        ch->enabled = state->digital_channels[i];
        }
 
+       /* According to the SCPI standard, the response to the command
+        * SCPI_CMD_GET_DIG_POD_THRESHOLD might return "USER" instead of
+        * "USER1".
+        *
+        * This makes more difficult to validate the response when the logic
+        * threshold is set to "USER1" and therefore we need to prevent device
+        * opening failures in such configuration case...
+        */
+       for (i = 0; i < config->num_logic_threshold; i++) {
+               logic_threshold_short[i] = g_strdup((*config->logic_threshold)[i]);
+               if (!strcmp("USER1", (*config->logic_threshold)[i]))
+                       g_strlcpy(logic_threshold_short[i],
+                                 (*config->logic_threshold)[i], strlen((*config->logic_threshold)[i]));
+       }
+
        for (i = 0; i < config->digital_pods; i++) {
                g_snprintf(command, sizeof(command),
                           (*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_STATE],
                           i + 1);
 
                if (sr_scpi_get_bool(scpi, command,
-                                    &state->digital_pods[i]) != SR_OK)
-                       return SR_ERR;
+                                    &state->digital_pods[i].state) != SR_OK)
+                       goto exit;
+
+               g_snprintf(command, sizeof(command),
+                          (*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_THRESHOLD],
+                          i + 1);
+
+               /* Check for both standard and shortened responses. */
+               if (scope_state_get_array_option(scpi, command, config->logic_threshold,
+                                                config->num_logic_threshold,
+                                                &state->digital_pods[i].threshold) != SR_OK)
+                       if (scope_state_get_array_option(scpi, command, (const char * (*)[]) &logic_threshold_short,
+                                                        config->num_logic_threshold,
+                                                        &state->digital_pods[i].threshold) != SR_OK)
+                               goto exit;
+
+               if (!strcmp("USER1", (*config->logic_threshold)[state->digital_pods[i].threshold]))
+                       g_snprintf(command, sizeof(command),
+                                  (*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_USER_THRESHOLD],
+                                  i + 1, 1); // USER1 logic threshold setting
+
+               if (!strcmp("USER2", (*config->logic_threshold)[state->digital_pods[i].threshold]))
+                       g_snprintf(command, sizeof(command),
+                                  (*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_USER_THRESHOLD],
+                                  i + 1, 2); // USER2 for custom logic_threshold setting
+
+               if (!strcmp("USER1", (*config->logic_threshold)[state->digital_pods[i].threshold]) ||
+                   !strcmp("USER2", (*config->logic_threshold)[state->digital_pods[i].threshold]))
+                       if (sr_scpi_get_float(scpi, command,
+                           &state->digital_pods[i].user_threshold) != SR_OK)
+                               goto exit;
        }
 
-       return SR_OK;
+       result = SR_OK;
+
+exit:
+       for (i = 0; i < config->num_logic_threshold; i++)
+               g_free(logic_threshold_short[i]);
+
+       return result;
 }
 
 SR_PRIV int hmo_update_sample_rate(const struct sr_dev_inst *sdi)
@@ -579,7 +680,7 @@ SR_PRIV int hmo_update_sample_rate(const struct sr_dev_inst *sdi)
 
        if (!channel_found) {
                for (i = 0; i < config->digital_pods; i++) {
-                       if (!state->digital_pods[i])
+                       if (!state->digital_pods[i].state)
                                continue;
                        g_snprintf(chan_name, sizeof(chan_name), "POD%d", i);
                        g_snprintf(tmp_str, sizeof(tmp_str),
@@ -692,7 +793,7 @@ static struct scope_state *scope_state_new(const struct scope_config *config)
        state->digital_channels = g_malloc0_n(
                        config->digital_channels, sizeof(gboolean));
        state->digital_pods = g_malloc0_n(config->digital_pods,
-                       sizeof(gboolean));
+                       sizeof(struct digital_pod_state));
 
        return state;
 }
index 8620dedc632ed55d760c98299e88673e635d7ffe..da48ce9a65ee484198a051823282dfadf474ee49 100644 (file)
@@ -49,9 +49,15 @@ struct scope_config {
        const uint32_t (*devopts_cg_analog)[];
        const uint8_t num_devopts_cg_analog;
 
+       const uint32_t (*devopts_cg_digital)[];
+       const uint8_t num_devopts_cg_digital;
+
        const char *(*coupling_options)[];
        const uint8_t num_coupling_options;
 
+       const char *(*logic_threshold)[];
+       const uint8_t num_logic_threshold;
+
        const char *(*trigger_sources)[];
        const uint8_t num_trigger_sources;
 
@@ -80,10 +86,17 @@ struct analog_channel_state {
        char probe_unit;
 };
 
+struct digital_pod_state {
+       gboolean state;
+
+       int threshold;
+       float user_threshold;
+};
+
 struct scope_state {
        struct analog_channel_state *analog_channels;
        gboolean *digital_channels;
-       gboolean *digital_pods;
+       struct digital_pod_state *digital_pods;
 
        int timebase;
        float horiz_triggerpos;
index 88e3532a00f22c0cd6c9887b066fcc42eee4afb5..d5c92313b9901cf8be578ab433b792ffc79d63bb 100644 (file)
@@ -121,6 +121,10 @@ static struct sr_key_info sr_key_info_config[] = {
                "Hold min", NULL},
        {SR_CONF_VOLTAGE_THRESHOLD, SR_T_DOUBLE_RANGE, "voltage_threshold",
                "Voltage threshold", NULL },
+       {SR_CONF_LOGIC_THRESHOLD, SR_T_STRING, "logic_threshold",
+               "Logic threshold (predefined)", NULL},
+       {SR_CONF_LOGIC_THRESHOLD_CUSTOM, SR_T_FLOAT, "logic_threshold_custom",
+               "Logic threshold (custom)", NULL},
        {SR_CONF_EXTERNAL_CLOCK, SR_T_BOOL, "external_clock",
                "External clock mode", NULL},
        {SR_CONF_SWAP, SR_T_BOOL, "swap",
index 5d0459ffd88aad283363b71f29bdc218d384ebfc..d921133efcc5fd82fe6817ccbf37fd968eccc885 100644 (file)
@@ -63,6 +63,10 @@ enum {
        SCPI_CMD_SET_PROBE_UNIT,
        SCPI_CMD_GET_ANALOG_CHAN_NAME,
        SCPI_CMD_GET_DIG_CHAN_NAME,
+       SCPI_CMD_GET_DIG_POD_THRESHOLD,
+       SCPI_CMD_SET_DIG_POD_THRESHOLD,
+       SCPI_CMD_GET_DIG_POD_USER_THRESHOLD,
+       SCPI_CMD_SET_DIG_POD_USER_THRESHOLD,
 };
 
 enum scpi_transport_layer {