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

This second version (v2) of the patch improves the code while at
the same time it prevents device opening failures caused by a bug
which affects the latest HMO3000 firmware (V6.005) and which
causes the oscilloscope to send the wrong "USER" string instead of
the correct "USER1" string for the user-defined POD (Logic)
Threshold.

Signed-off-by: Guido Trentalancia <gu...@trentalancia.com>
---
 include/libsigrok/libsigrok.h     |    5 ++
 src/hardware/hameg-hmo/api.c      |   45 +++++++++++++++++++++-
 src/hardware/hameg-hmo/protocol.c |   75 ++++++++++++++++++++++++++++++++++----
 src/hardware/hameg-hmo/protocol.h |   14 ++++++-
 src/hwdriver.c                    |    2 +
 src/scpi.h                        |    2 +
 6 files changed, 133 insertions(+), 10 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-10-20 
13:12:30.841966966 +0200
+++ libsigrok-git-logic-threshold/include/libsigrok/libsigrok.h 2018-11-12 
14:25:42.746957911 +0100
@@ -827,9 +827,12 @@ enum sr_configkey {
        /** Min hold mode. */
        SR_CONF_HOLD_MIN,
 
-       /** Logic low-high threshold range. */
+       /** Logic low-high threshold: numerical value. */
        SR_CONF_VOLTAGE_THRESHOLD,
 
+       /** Logic low-high threshold: predefined levels (TTL, ECL, CMOS, etc). 
*/
+       SR_CONF_LOGIC_THRESHOLD,
+
        /** 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-11 
15:13:10.929161841 +0100
+++ libsigrok-git-logic-threshold/src/hardware/hameg-hmo/api.c  2018-11-12 
14:25:42.747957911 +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,17 @@ 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;
        default:
                return SR_ERR_NA;
        }
@@ -332,6 +344,26 @@ 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;
        default:
                ret = SR_ERR_NA;
                break;
@@ -373,6 +405,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 +440,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 +609,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 +618,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-11 
15:12:40.687162919 +0100
+++ libsigrok-git-logic-threshold/src/hardware/hameg-hmo/protocol.c     
2018-11-12 16:59:47.832837472 +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
@@ -55,6 +56,8 @@ static const char *hameg_scpi_dialect[]
        [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",
 };
 
 static const uint32_t devopts[] = {
@@ -75,6 +78,10 @@ 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,
+};
+
 static const char *coupling_options[] = {
        "AC",  // AC with 50 Ohm termination (152x, 202x, 30xx, 1202)
        "ACL", // AC with 1 MOhm termination
@@ -89,6 +96,14 @@ static const char *scope_trigger_slopes[
        "EITH",
 };
 
+static const char *logic_threshold[] = {
+       "TTL",
+       "ECL",
+       "CMOS",
+       "USER1",
+       "USER2",
+};
+
 /* HMO compact2 */
 static const char *an2_dig8_trigger_sources[] = {
        "CH1", "CH2",
@@ -204,9 +219,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 +261,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 +302,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 +343,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 +392,9 @@ 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");
+               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]);
        }
 
        tmp = sr_period_string((*config->timebases)[state->timebase][0],
@@ -517,7 +557,7 @@ static int digital_channel_state_get(str
                                     const struct scope_config *config,
                                     struct scope_state *state)
 {
-       unsigned int i;
+       unsigned int i, logic_threshold_user1_idx = 0;
        char command[MAX_COMMAND_SIZE];
        struct sr_channel *ch;
        struct sr_scpi_dev_inst *scpi = sdi->conn;
@@ -536,14 +576,37 @@ static int digital_channel_state_get(str
                        ch->enabled = state->digital_channels[i];
        }
 
+       /* A bug affects the latest HMO3000 firmware (V6.005) so that the SCPI
+        * command SCPI_CMD_GET_DIG_POD_THRESHOLD wrongly returns "USER" instead
+        * of "USER1" !
+        *
+        * This makes impossible 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++)
+               if (!strcmp("USER1", (*config->logic_threshold)[i])) {
+                       logic_threshold_user1_idx = i;
+                       break;
+               }
+
        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)
+                                    &state->digital_pods[i].state) != SR_OK)
                        return SR_ERR;
+
+               g_snprintf(command, sizeof(command),
+                          
(*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_THRESHOLD],
+                          i + 1);
+
+               if (scope_state_get_array_option(scpi, command, 
config->logic_threshold,
+                                                config->num_logic_threshold,
+                                                
&state->digital_pods[i].threshold) != SR_OK)
+                       state->digital_pods[i].threshold = 
logic_threshold_user1_idx; // firmware bug
        }
 
        return SR_OK;
@@ -579,7 +642,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 +755,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-11 
15:12:40.688162919 +0100
+++ libsigrok-git-logic-threshold/src/hardware/hameg-hmo/protocol.h     
2018-11-12 14:25:42.749957911 +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,16 @@ struct analog_channel_state {
        char probe_unit;
 };
 
+struct digital_pod_state {
+       gboolean state;
+
+       int 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-10-20 13:12:30.965966965 +0200
+++ libsigrok-git-logic-threshold/src/hwdriver.c        2018-11-12 
14:25:42.750957911 +0100
@@ -121,6 +121,8 @@ 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", 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-11 14:37:51.385675625 +0100
+++ libsigrok-git-logic-threshold/src/scpi.h    2018-11-12 14:25:42.750957911 
+0100
@@ -63,6 +63,8 @@ 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,
 };
 
 struct scpi_command {


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

Reply via email to