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

The second version (v2) of this patch improved the code while at
the same time it prevented device opening failures caused by the
fact that the SCPI standard allows shortened responses (e.g. "USER"
instead of "USER1").

The third version (v3) of this patch introduced fully custom logic
threshold configuration (i.e. numerical values) in addition to the
predefined levels, for example:

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

This fourth version (v4) improves the handling of shorted responses
and does no longer incorrectly refer to such behaviour as a
"firmware bug" in the comments.

Signed-off-by: Guido Trentalancia <gu...@trentalancia.com>
---
 include/libsigrok/libsigrok.h     |    6 +
 src/hardware/hameg-hmo/api.c      |   86 +++++++++++++++++++
 src/hardware/hameg-hmo/protocol.c |  167 ++++++++++++++++++++++++++++++--------
 src/hardware/hameg-hmo/protocol.h |   15 +++
 src/hwdriver.c                    |    4 
 src/scpi.h                        |    4 
 6 files changed, 246 insertions(+), 36 deletions(-)

diff -pru libsigrok-git-orig/include/libsigrok/libsigrok.h 
libsigrok-git-logic-threshold/include/libsigrok/libsigrok.h
--- libsigrok-git-orig/include/libsigrok/libsigrok.h    2018-11-13 
08:21:41.840043800 +0100
+++ libsigrok-git-logic-threshold/include/libsigrok/libsigrok.h 2018-11-13 
08:24:48.963552135 +0100
@@ -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,
 
diff -pru libsigrok-git-orig/src/hardware/hameg-hmo/api.c 
libsigrok-git-logic-threshold/src/hardware/hameg-hmo/api.c
--- libsigrok-git-orig/src/hardware/hameg-hmo/api.c     2018-11-13 
08:21:41.848047800 +0100
+++ libsigrok-git-logic-threshold/src/hardware/hameg-hmo/api.c  2018-11-13 
08:24:48.964552635 +0100
@@ -2,6 +2,7 @@
  * This file is part of the libsigrok project.
  *
  * Copyright (C) 2013 poljar (Damir Jelić) <poljari...@gmail.com>
+ * Copyright (C) 2018 Guido Trentalancia <gu...@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, GVar
        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, GVar
                        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, GVa
                                *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, GVa
                        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 stru
 
        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 stru
                        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);
diff -pru libsigrok-git-orig/src/hardware/hameg-hmo/protocol.c 
libsigrok-git-logic-threshold/src/hardware/hameg-hmo/protocol.c
--- libsigrok-git-orig/src/hardware/hameg-hmo/protocol.c        2018-11-13 
08:21:41.867057299 +0100
+++ libsigrok-git-logic-threshold/src/hardware/hameg-hmo/protocol.c     
2018-11-13 18:51:58.339047302 +0100
@@ -2,6 +2,7 @@
  * This file is part of the libsigrok project.
  *
  * Copyright (C) 2013 poljar (Damir Jelić) <poljari...@gmail.com>
+ * Copyright (C) 2018 Guido Trentalancia <gu...@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(struc
 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_m
                .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_m
                .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_m
                .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_m
                .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 struc
        }
 
        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(str
                                     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(str
                        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;
 
-       return SR_OK;
+               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;
+       }
+
+       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
 
        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_n
        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;
 }
diff -pru libsigrok-git-orig/src/hardware/hameg-hmo/protocol.h 
libsigrok-git-logic-threshold/src/hardware/hameg-hmo/protocol.h
--- libsigrok-git-orig/src/hardware/hameg-hmo/protocol.h        2018-11-13 
08:21:41.871059299 +0100
+++ libsigrok-git-logic-threshold/src/hardware/hameg-hmo/protocol.h     
2018-11-13 08:24:48.966553635 +0100
@@ -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;
diff -pru libsigrok-git-orig/src/hwdriver.c 
libsigrok-git-logic-threshold/src/hwdriver.c
--- libsigrok-git-orig/src/hwdriver.c   2018-11-13 08:21:41.873060299 +0100
+++ libsigrok-git-logic-threshold/src/hwdriver.c        2018-11-13 
08:24:48.967554135 +0100
@@ -121,6 +121,10 @@ static struct sr_key_info sr_key_info_co
                "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",
diff -pru libsigrok-git-orig/src/scpi.h libsigrok-git-logic-threshold/src/scpi.h
--- libsigrok-git-orig/src/scpi.h       2018-11-13 08:21:41.882064799 +0100
+++ libsigrok-git-logic-threshold/src/scpi.h    2018-11-13 08:24:48.968554635 
+0100
@@ -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,
 };
 
 struct scpi_command {


_______________________________________________
sigrok-devel mailing list
sigrok-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to