From 4b78fed299cd730c81172f4e22b313edfa7b7f7a Mon Sep 17 00:00:00 2001
From: Daniel <1824222@stud.hs-mannheim.de>
Date: Sat, 7 Jan 2023 09:19:58 +0100
Subject: [PATCH 1/9] initial commit for WIP Agilent 54621d driver
---
Makefile.am | 6 +
configure.ac | 1 +
src/hardware/agilent-54621d/api.c | 692 ++++++++++++++++++++++++
src/hardware/agilent-54621d/protocol.c | 712 +++++++++++++++++++++++++
src/hardware/agilent-54621d/protocol.h | 153 ++++++
src/scpi/scpi.c | 1 +
6 files changed, 1565 insertions(+)
create mode 100644 src/hardware/agilent-54621d/api.c
create mode 100644 src/hardware/agilent-54621d/protocol.c
create mode 100644 src/hardware/agilent-54621d/protocol.h
diff --git a/Makefile.am b/Makefile.am
index 280cf64d2..6fac3f968 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -226,6 +226,12 @@ src_libdrivers_tail_la_SOURCES = src/driver_list_stop.c
src_libdrivers_la_SOURCES = src/drivers.c
+if HW_AGILENT_54621D
+src_libdrivers_la_SOURCES += \
+ src/hardware/agilent-54621d/protocol.h \
+ src/hardware/agilent-54621d/protocol.c \
+ src/hardware/agilent-54621d/api.c
+endif
if HW_AGILENT_DMM
src_libdrivers_la_SOURCES += \
src/hardware/agilent-dmm/protocol.h \
diff --git a/configure.ac b/configure.ac
index 3ba6c8c5d..09aee65f0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -290,6 +290,7 @@ m4_define([_SR_DRIVER], [
m4_define([SR_DRIVER],
[_SR_DRIVER([$1], [$2], m4_expand([AS_TR_CPP([HW_$2])]), [$3])])
+SR_DRIVER([Agilent 54621D], [agilent-54621d])
SR_DRIVER([Agilent DMM], [agilent-dmm], [serial_comm])
SR_DRIVER([Appa 55II], [appa-55ii], [serial_comm])
SR_DRIVER([Arachnid Labs Re:load Pro], [arachnid-labs-re-load-pro], [serial_comm])
diff --git a/src/hardware/agilent-54621d/api.c b/src/hardware/agilent-54621d/api.c
new file mode 100644
index 000000000..9ef63f6a1
--- /dev/null
+++ b/src/hardware/agilent-54621d/api.c
@@ -0,0 +1,692 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2022 Daniel <1824222@stud.hs-mannheim.de>
+ *
+ * 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 .
+ */
+
+#include
+#include "protocol.h"
+#include "scpi.h"
+
+static struct sr_dev_driver agilent_54621d_driver_info;
+
+static const char *manufacturers[] = {
+ "AGILENT TECHNOLOGIES",
+};
+
+static const uint32_t scanopts[] = {
+ SR_CONF_CONN,
+ SR_CONF_SERIALCOMM,
+};
+
+static const uint32_t drvopts[] = {
+ SR_CONF_OSCILLOSCOPE,
+ SR_CONF_LOGIC_ANALYZER,
+};
+
+enum {
+ CG_INVALID = -1,
+ CG_NONE,
+ CG_ANALOG,
+ CG_DIGITAL,
+};
+
+static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
+{
+ struct sr_dev_inst *sdi;
+ struct dev_context *devc;
+ struct sr_scpi_hw_info *hw_info;
+
+ if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
+ sr_info("Couldn't get IDN response.");
+ goto fail;
+ }
+
+ if (std_str_idx_s(hw_info->manufacturer, ARRAY_AND_SIZE(manufacturers)) < 0)
+ goto fail;
+
+ sdi = g_malloc0(sizeof(struct sr_dev_inst));
+ sdi->vendor = g_strdup(hw_info->manufacturer);
+ sdi->model = g_strdup(hw_info->model);
+ sdi->version = g_strdup(hw_info->firmware_version);
+ sdi->serial_num = g_strdup(hw_info->serial_number);
+ sdi->driver = &agilent_54621d_driver_info;
+ sdi->inst_type = SR_INST_SCPI;
+ sdi->conn = scpi;
+
+ sr_scpi_hw_info_free(hw_info);
+ hw_info = NULL;
+
+ devc = g_malloc0(sizeof(struct dev_context));
+
+ sdi->priv = devc;
+
+ if (agilent_54621d_init_device(sdi) != SR_OK)
+ goto fail;
+
+ return sdi;
+
+fail:
+ sr_scpi_hw_info_free(hw_info);
+ sr_dev_inst_free(sdi);
+ g_free(devc);
+
+ return NULL;
+}
+
+static GSList *scan(struct sr_dev_driver *di, GSList *options)
+{
+ sr_info("Scanning for agilent 54621d");
+ return sr_scpi_scan(di->context, options, probe_device);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+ int ret;
+ struct sr_scpi_dev_inst *scpi = sdi->conn;
+
+ if ((ret = sr_scpi_open(scpi)) < 0) {
+ sr_err("Failed to open SCPI device: %s.", sr_strerror(ret));
+ return SR_ERR;
+ }
+
+ if ((ret = agilent_54621d_scope_state_get(sdi)) < 0) {
+ sr_err("Failed to get device config: %s.", sr_strerror(ret));
+ return SR_ERR;
+ }
+
+ return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+ return sr_scpi_close(sdi->conn);
+}
+
+static int check_channel_group(struct dev_context *devc,
+ const struct sr_channel_group *cg)
+{
+ const struct scope_config *model;
+
+ model = devc->model_config;
+
+ if (!cg)
+ return CG_NONE;
+
+ if (std_cg_idx(cg, devc->analog_groups, model->analog_channels) >= 0)
+ return CG_ANALOG;
+
+ if (std_cg_idx(cg, devc->digital_groups, model->digital_pods) >= 0)
+ return CG_DIGITAL;
+
+ sr_err("Invalid channel group specified.");
+
+ return CG_INVALID;
+}
+
+static int config_get(uint32_t key, GVariant **data,
+ const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
+{
+ int cg_type, idx, i;
+ struct dev_context *devc;
+ const struct scope_config *model;
+ struct scope_state *state;
+
+ if (!sdi)
+ return SR_ERR_ARG;
+
+ devc = sdi->priv;
+
+ if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
+ return SR_ERR;
+
+ model = devc->model_config;
+ state = devc->model_state;
+
+ switch (key) {
+ case SR_CONF_NUM_HDIV:
+ *data = g_variant_new_int32(model->num_xdivs);
+ break;
+ case SR_CONF_TIMEBASE:
+ *data = g_variant_new("(tt)", (*model->timebases)[state->timebase][0],
+ (*model->timebases)[state->timebase][1]);
+ break;
+ case SR_CONF_NUM_VDIV:
+ if (!cg)
+ return SR_ERR_CHANNEL_GROUP;
+ if (cg_type != CG_ANALOG)
+ return SR_ERR_NA;
+ if (std_cg_idx(cg, devc->analog_groups, model->analog_channels) < 0)
+ return SR_ERR_ARG;
+ *data = g_variant_new_int32(model->num_ydivs);
+ break;
+ case SR_CONF_VDIV:
+ if (!cg)
+ return SR_ERR_CHANNEL_GROUP;
+ if (cg_type != CG_ANALOG)
+ return SR_ERR_NA;
+ if ((idx = std_cg_idx(cg, devc->analog_groups, model->analog_channels)) < 0)
+ return SR_ERR_ARG;
+ *data = g_variant_new("(tt)",
+ (*model->vdivs)[state->analog_channels[idx].vdiv][0],
+ (*model->vdivs)[state->analog_channels[idx].vdiv][1]);
+ break;
+ case SR_CONF_TRIGGER_SOURCE:
+ *data = g_variant_new_string((*model->trigger_sources)[state->trigger_source]);
+ break;
+ case SR_CONF_TRIGGER_SLOPE:
+ *data = g_variant_new_string((*model->trigger_slopes)[state->trigger_slope]);
+ break;
+ case SR_CONF_PEAK_DETECTION:
+ *data = g_variant_new_boolean(state->peak_detection);
+ break;
+ case SR_CONF_HORIZ_TRIGGERPOS:
+ *data = g_variant_new_double(state->horiz_triggerpos);
+ break;
+ case SR_CONF_ENABLED:
+ sr_info("get channel enabled");
+ if (!cg)
+ return SR_ERR_CHANNEL_GROUP;
+ if (cg_type == CG_DIGITAL){
+ sr_info("get digital channel enabled");
+ if ((idx = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
+ return SR_ERR_ARG;
+ *data = g_variant_new_boolean(state->digital_pods[idx].state);
+ }
+ else if (cg_type == CG_ANALOG){
+ sr_info("get analog channel enabled");
+ if ((idx = std_cg_idx(cg, devc->analog_groups, model->analog_channels)) < 0)
+ return SR_ERR_ARG;
+ *data = g_variant_new_boolean(state->analog_channels[idx].state);
+ } else {
+ return SR_ERR;
+ }
+ break;
+ case SR_CONF_COUPLING:
+ if (!cg)
+ return SR_ERR_CHANNEL_GROUP;
+ if (cg_type != CG_ANALOG)
+ return SR_ERR_NA;
+ if ((idx = std_cg_idx(cg, devc->analog_groups, model->analog_channels)) < 0)
+ return SR_ERR_ARG;
+ *data = g_variant_new_string((*model->coupling_options)[state->analog_channels[idx].coupling]);
+ break;
+ 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;
+ *data = g_variant_new_double(state->digital_pods[idx].user_threshold);
+ break;
+ case SR_CONF_LIMIT_SAMPLES:
+ *data = g_variant_new_uint64(devc->samples_limit);
+ break;
+ //ToDo: Check if all options are implemented
+ default:
+ sr_err("could not find requested parameter: %d", key);
+ 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)
+{
+ int ret, cg_type, idx, i, j;
+ char command[MAX_COMMAND_SIZE], command2[MAX_COMMAND_SIZE];
+ char float_str[30], *tmp_str;
+ struct dev_context *devc;
+ const struct scope_config *model;
+ struct scope_state *state;
+ double tmp_d, tmp_d2;
+ gboolean update_sample_rate, tmp_bool;
+
+ if (!sdi)
+ return SR_ERR_ARG;
+
+ devc = sdi->priv;
+
+ if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
+ return SR_ERR;
+
+ model = devc->model_config;
+ state = devc->model_state;
+ update_sample_rate = FALSE;
+
+ switch (key) {
+ case SR_CONF_LIMIT_SAMPLES:
+ devc->samples_limit = g_variant_get_uint64(data);
+ ret = SR_OK;
+ break;
+ case SR_CONF_VDIV:
+ if (!cg)
+ return SR_ERR_CHANNEL_GROUP;
+ if ((idx = std_u64_tuple_idx(data, *model->vdivs, model->num_vdivs)) < 0)
+ return SR_ERR_ARG;
+ if ((j = std_cg_idx(cg, devc->analog_groups, model->analog_channels)) < 0)
+ return SR_ERR_ARG;
+ g_ascii_formatd(float_str, sizeof(float_str), "%E",
+ (float) (*model->vdivs)[idx][0] / (*model->vdivs)[idx][1]);
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_VERTICAL_SCALE],
+ j + 1, float_str);
+ if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+ sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ state->analog_channels[j].vdiv = idx;
+ ret = SR_OK;
+ break;
+ case SR_CONF_TIMEBASE:
+ if ((idx = std_u64_tuple_idx(data, *model->timebases, model->num_timebases)) < 0)
+ return SR_ERR_ARG;
+ g_ascii_formatd(float_str, sizeof(float_str), "%E",
+ (float) (*model->timebases)[idx][0] / (*model->timebases)[idx][1]);
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_TIMEBASE],
+ float_str);
+ if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+ sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ state->timebase = idx;
+ ret = SR_OK;
+ update_sample_rate = TRUE;
+ break;
+ case SR_CONF_HORIZ_TRIGGERPOS:
+ tmp_d = g_variant_get_double(data);
+ if (tmp_d < 0.0 || tmp_d > 1.0)
+ return SR_ERR;
+ tmp_d2 = -(tmp_d - 0.5) *
+ ((double) (*model->timebases)[state->timebase][0] /
+ (*model->timebases)[state->timebase][1])
+ * model->num_xdivs;
+ g_ascii_formatd(float_str, sizeof(float_str), "%E", tmp_d2);
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_HORIZ_TRIGGERPOS],
+ float_str);
+ if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+ sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ state->horiz_triggerpos = tmp_d;
+ ret = SR_OK;
+ break;
+ case SR_CONF_TRIGGER_SOURCE:
+ if ((idx = std_str_idx(data, *model->trigger_sources, model->num_trigger_sources)) < 0)
+ return SR_ERR_ARG;
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SOURCE],
+ (*model->trigger_sources)[idx]);
+ if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+ sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ state->trigger_source = idx;
+ ret = SR_OK;
+ break;
+ case SR_CONF_TRIGGER_SLOPE:
+ if ((idx = std_str_idx(data, *model->trigger_slopes, model->num_trigger_slopes)) < 0)
+ return SR_ERR_ARG;
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SLOPE],
+ (*model->trigger_slopes)[idx]);
+ if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+ sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ state->trigger_slope = idx;
+ ret = SR_OK;
+ break;
+ case SR_CONF_PEAK_DETECTION:
+ tmp_bool = g_variant_get_boolean(data);
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_PEAK_DETECTION],
+ tmp_bool ? "AUTO" : "OFF");
+ if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+ sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ /* Peak Detection automatically switches off High Resolution mode. */
+ if (tmp_bool) {
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_HIGH_RESOLUTION],
+ "OFF");
+ if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+ sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ state->high_resolution = FALSE;
+ }
+ state->peak_detection = tmp_bool;
+ ret = SR_OK;
+ break;
+ case SR_CONF_ENABLED:
+ if (!cg)
+ return SR_ERR_CHANNEL_GROUP;
+ if (cg_type == CG_DIGITAL){
+ if ((j = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
+ return SR_ERR_ARG;
+ //enable digital channel
+ }
+ else if (cg_type == CG_ANALOG){
+ if ((j = std_cg_idx(cg, devc->analog_groups, model->analog_channels)) < 0)
+ return SR_ERR_ARG;
+ g_snprintf(command, sizeof(command), (*model->scpi_dialect)[SCPI_CMD_SET_ANALOG_CHAN_STATE], j+1, g_variant_get_boolean(data));
+ if(sr_scpi_send(sdi->conn, command) != SR_OK || sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ state->analog_channels[j].state = g_variant_get_boolean(data);
+ update_sample_rate = TRUE;
+ ret = SR_OK;
+ //enable analog channel
+ } else {
+ return SR_ERR;
+ }
+ break;
+ case SR_CONF_COUPLING:
+ if (!cg)
+ return SR_ERR_CHANNEL_GROUP;
+ if ((idx = std_str_idx(data, *model->coupling_options, model->num_coupling_options)) < 0)
+ return SR_ERR_ARG;
+ if ((j = std_cg_idx(cg, devc->analog_groups, model->analog_channels)) < 0)
+ return SR_ERR_ARG;
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_COUPLING],
+ j + 1, (*model->coupling_options)[idx]);
+ if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+ sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ state->analog_channels[j].coupling = idx;
+ 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;
+ /* Check if the threshold command is based on the POD or digital channel index. */
+ if (model->logic_threshold_for_pod)
+ i = j + 1;
+ else
+ i = j * DIGITAL_CHANNELS_PER_POD;
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
+ i, (*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);
+ /* Check if the threshold command is based on the POD or digital channel index. */
+ if (model->logic_threshold_for_pod)
+ idx = j + 1;
+ else
+ idx = j * DIGITAL_CHANNELS_PER_POD;
+ /* Try to support different dialects exhaustively. */
+ for (i = 0; i < model->num_logic_threshold; i++) {
+ if (!strcmp("USER2", (*model->logic_threshold)[i])) {
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
+ idx, 2, float_str); /* USER2 */
+ g_snprintf(command2, sizeof(command2),
+ (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
+ idx, "USER2");
+ break;
+ }
+ if (!strcmp("USER", (*model->logic_threshold)[i])) {
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
+ idx, float_str);
+ g_snprintf(command2, sizeof(command2),
+ (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
+ idx, "USER");
+ break;
+ }
+ if (!strcmp("MAN", (*model->logic_threshold)[i])) {
+ g_snprintf(command, sizeof(command),
+ (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
+ idx, float_str);
+ g_snprintf(command2, sizeof(command2),
+ (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
+ idx, "MAN");
+ break;
+ }
+ }
+ if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+ sr_scpi_get_opc(sdi->conn) != SR_OK)
+ return SR_ERR;
+ if (sr_scpi_send(sdi->conn, command2) != 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;
+ }
+
+ if (ret == SR_OK && update_sample_rate)
+ ret = agilent_54621d_update_sample_rate(sdi);
+
+ return ret;
+}
+
+static int config_list(uint32_t key, GVariant **data,
+ const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
+{
+ int ret;
+
+ int cg_type = CG_NONE;
+ struct dev_context *devc = NULL;
+ const struct scope_config *model = NULL;
+
+ if (sdi) {
+ devc = sdi->priv;
+ if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
+ return SR_ERR;
+
+ model = devc->model_config;
+ }
+
+ ret = SR_OK;
+ switch (key) {
+ case SR_CONF_SCAN_OPTIONS:
+ *data = std_gvar_array_u32(ARRAY_AND_SIZE(scanopts));
+ break;
+ case SR_CONF_DEVICE_OPTIONS:
+ if (!cg) {
+ if (model)
+ *data = std_gvar_array_u32(*model->devopts, model->num_devopts);
+ else
+ *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);
+ }
+ break;
+ case SR_CONF_COUPLING:
+ if (!cg)
+ return SR_ERR_CHANNEL_GROUP;
+ if (!model)
+ return SR_ERR_ARG;
+ *data = g_variant_new_strv(*model->coupling_options, model->num_coupling_options);
+ break;
+ case SR_CONF_TRIGGER_SOURCE:
+ if (!model)
+ return SR_ERR_ARG;
+ *data = g_variant_new_strv(*model->trigger_sources, model->num_trigger_sources);
+ break;
+ case SR_CONF_TRIGGER_SLOPE:
+ if (!model)
+ return SR_ERR_ARG;
+ *data = g_variant_new_strv(*model->trigger_slopes, model->num_trigger_slopes);
+ break;
+ case SR_CONF_TIMEBASE:
+ if (!model)
+ return SR_ERR_ARG;
+ *data = std_gvar_tuple_array(*model->timebases, model->num_timebases);
+ break;
+ case SR_CONF_VDIV:
+ if (!cg)
+ return SR_ERR_CHANNEL_GROUP;
+ if (!model)
+ 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;
+ /* TODO Check if all relevant option are present here */
+ default:
+ sr_info("Trying to query for config list for:");
+ return SR_ERR_NA;
+ }
+
+ return ret;
+}
+
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi)
+{
+ GSList *l;
+ struct sr_channel *ch;
+ struct dev_context *devc;
+ struct sr_scpi_dev_inst *scpi;
+ struct scope_state *state;
+ const struct scope_config *model;
+ int ret;
+ char *cmd;
+ gboolean state_changed;
+
+ scpi = sdi->conn;
+ devc = sdi->priv;
+ state = devc->model_state;
+ model = devc->model_config;
+
+ devc->num_samples = 0;
+ devc->num_frames = 0;
+
+ devc->enabled_channels = NULL;
+ state_changed = FALSE;
+
+ for (l = sdi->channels; l; l = l->next) {
+ ch = l->data;
+ sr_dbg("initializing channel %s", ch->name);
+ if(ch->type == SR_CHANNEL_ANALOG) {
+ if(ch->enabled)
+ devc->enabled_channels = g_slist_append(devc->enabled_channels, ch);
+ //Enable/disable channel if neccessary
+ if(ch->enabled != state->analog_channels[ch->index].state) {
+ if( sr_scpi_send(scpi, (*model->scpi_dialect)[SCPI_CMD_SET_ANALOG_CHAN_STATE], ch->index + 1, ch->enabled ? "ON" : "OFF") != SR_OK ||
+ sr_scpi_get_opc(scpi) != SR_OK)
+ return SR_ERR;
+ state->analog_channels[ch->index].state = ch->enabled;
+ state_changed = TRUE;
+ }
+ } else if (ch->type == SR_CHANNEL_LOGIC) {
+ devc->enabled_channels = g_slist_append(devc->enabled_channels, ch);
+ //Enable/disable channel if neccessary
+ if(ch->enabled != state->digital_channels[ch->index]) {
+ if( sr_scpi_send(scpi, (*model->scpi_dialect)[SCPI_CMD_SET_DIG_CHAN_STATE], ch->index, ch->enabled ? "ON" : "OFF") != SR_OK ||
+ sr_scpi_get_opc(scpi) != SR_OK)
+ return SR_ERR;
+ state->digital_channels[ch->index] = ch->enabled;
+ state_changed = TRUE;
+ }
+ }
+ }
+
+ //Sample rate needs to be updated if channels have been changed, since in some channel configurations sample rate is reduced
+ if(state_changed)
+ if(agilent_54621d_update_sample_rate(sdi) != SR_OK)
+ return SR_ERR;
+
+ //ToDo: Start capture
+
+ std_session_send_df_header(sdi);
+
+ return SR_OK;
+
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi)
+{
+ /* TODO: stop acquisition. */
+
+ (void)sdi;
+
+ return SR_OK;
+}
+
+static struct sr_dev_driver agilent_54621d_driver_info = {
+ .name = "agilent-54621d",
+ .longname = "Agilent 54621D",
+ .api_version = 1,
+ .init = std_init,
+ .cleanup = std_cleanup,
+ .scan = scan,
+ .dev_list = std_dev_list,
+ .dev_clear = std_dev_clear,
+ .config_get = config_get,
+ .config_set = config_set,
+ .config_list = config_list,
+ .dev_open = dev_open,
+ .dev_close = dev_close,
+ .dev_acquisition_start = dev_acquisition_start,
+ .dev_acquisition_stop = dev_acquisition_stop,
+ .context = NULL,
+};
+SR_REGISTER_DEV_DRIVER(agilent_54621d_driver_info);
diff --git a/src/hardware/agilent-54621d/protocol.c b/src/hardware/agilent-54621d/protocol.c
new file mode 100644
index 000000000..14c437c43
--- /dev/null
+++ b/src/hardware/agilent-54621d/protocol.c
@@ -0,0 +1,712 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2022 Daniel <1824222@stud.hs-mannheim.de>
+ *
+ * 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 .
+ */
+
+#include
+#include "protocol.h"
+#include "scpi.h"
+
+#define MAX_COMMAND_SIZE 128
+#define LOGIC_GET_THRESHOLD_SETTING "USER" //Threshold Setting that should be reported by the driver. Has to be included in logic_threshold. Has to be done in that hacky way since the device does only report threshold voltage level, yet not threshold setting
+
+static const char *agilent_scpi_dialect[] = {
+ [SCPI_CMD_GET_DIG_DATA] = ":FORM UINT,8;:POD%d:DATA?",
+ [SCPI_CMD_GET_TIMEBASE] = ":TIM:SCAL?", //OK
+ [SCPI_CMD_SET_TIMEBASE] = ":TIM:SCAL %s", //OK
+ [SCPI_CMD_GET_COUPLING] = ":CHAN%d:COUP?", //OK
+ [SCPI_CMD_SET_COUPLING] = ":CHAN%d:COUP %s", //OK
+ [SCPI_CMD_GET_SAMPLE_RATE] = ":ACQ:SRAT?", //OK
+ [SCPI_CMD_GET_ANALOG_DATA] = ":FORM:BORD %s;" \
+ ":FORM REAL,32;:CHAN%d:DATA?",
+ [SCPI_CMD_GET_VERTICAL_SCALE] = ":CHAN%d:SCAL?", //OK
+ [SCPI_CMD_SET_VERTICAL_SCALE] = ":CHAN%d:SCAL %s", //OK
+ [SCPI_CMD_GET_DIG_POD_STATE] = ":POD%d:DISP?", //Fixed
+ [SCPI_CMD_SET_DIG_POD_STATE] = ":POD%d:DISP %d", //Fixed
+ [SCPI_CMD_GET_TRIGGER_SOURCE] = ":TRIG:SOUR?", //Fixed
+ [SCPI_CMD_SET_TRIGGER_SOURCE] = ":TRIG:SOUR %s", //Fixed
+ [SCPI_CMD_GET_TRIGGER_SLOPE] = ":TRIG:SLOP?", //Fixed
+ [SCPI_CMD_SET_TRIGGER_SLOPE] = ":TRIG:MODE EDGE;:TRIG:SLOP %s", //Fixed ?
+ [SCPI_CMD_GET_TRIGGER_PATTERN] = ":TRIG:A:PATT:SOUR?",
+ [SCPI_CMD_SET_TRIGGER_PATTERN] = ":TRIG:A:TYPE LOGIC;" \
+ ":TRIG:A:PATT:FUNC AND;" \
+ ":TRIG:A:PATT:COND \"TRUE\";" \
+ ":TRIG:A:PATT:MODE OFF;" \
+ ":TRIG:A:PATT:SOUR \"%s\"",
+ [SCPI_CMD_GET_HIGH_RESOLUTION] = ":ACQ:HRES?",
+ [SCPI_CMD_SET_HIGH_RESOLUTION] = ":ACQ:HRES %s",
+ [SCPI_CMD_GET_PEAK_DETECTION] = ":ACQ:TYPE?", //Fixed
+ [SCPI_CMD_SET_PEAK_DETECTION] = ":ACQ:TYPE PEAK", //Fixed
+ [SCPI_CMD_GET_DIG_CHAN_STATE] = ":DIG%d:DISP?", //Fixed
+ [SCPI_CMD_SET_DIG_CHAN_STATE] = ":DIG%d:DISP %s", //Fixed
+ [SCPI_CMD_GET_VERTICAL_OFFSET] = ":CHAN%d:OFFS?", //Fixed
+ [SCPI_CMD_GET_HORIZ_TRIGGERPOS] = ":TIM:POS?", //OK
+ [SCPI_CMD_SET_HORIZ_TRIGGERPOS] = ":TIM:POS %s", //OK
+ [SCPI_CMD_GET_ANALOG_CHAN_STATE] = ":CHAN%d:DISP?", //Fixed
+ [SCPI_CMD_SET_ANALOG_CHAN_STATE] = ":CHAN%d:DISP %s", //Fixed
+ [SCPI_CMD_GET_PROBE_UNIT] = ":CHAN%d:UNIT?", //Fixed
+ [SCPI_CMD_GET_DIG_POD_THRESHOLD] = ":POD%d:THR?", //OK
+ [SCPI_CMD_SET_DIG_POD_THRESHOLD] = ":POD%d:THR %s", //OK
+};
+
+static const uint32_t devopts[] = {
+ SR_CONF_OSCILLOSCOPE,
+ SR_CONF_SAMPLERATE | SR_CONF_GET,
+ SR_CONF_TIMEBASE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_NUM_HDIV | SR_CONF_GET,
+ SR_CONF_HORIZ_TRIGGERPOS | SR_CONF_GET | SR_CONF_SET,
+ SR_CONF_TRIGGER_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_TRIGGER_SLOPE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_TRIGGER_LEVEL | SR_CONF_GET | SR_CONF_SET,
+// SR_CONF_TRIGGER_PATTERN | SR_CONF_GET | SR_CONF_SET, //ToDo: Implement pattern trigger
+ SR_CONF_PEAK_DETECTION | SR_CONF_GET | SR_CONF_SET,
+// SR_CONF_AVERAGING | SR_CONF_GET | SR_CONF_SET,
+ SR_CONF_AVG_SAMPLES | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, //The device doesn't actually support limiting samples, but will allways capture the maximum available amout of samples. However the driver can selectively transfere a subset of samples inorder to reduce transfer times.
+};
+
+static const uint32_t devopts_cg_analog[] = {
+ SR_CONF_NUM_VDIV | SR_CONF_GET,
+ SR_CONF_VDIV | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_COUPLING | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
+ //SR_CONF_PROBE_FACTOR | 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,
+ SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
+};
+
+static const char *coupling_options[] = {
+ "AC",
+ "DC",
+ "GND",
+ //Agilent 5464x Scopes also allow 50Ohm Termination, however this is configured using the termination command. If someone wants to implement support for that you need to figure out the best way to do that
+};
+
+static const char *scope_trigger_slopes[] = {
+ "POS",
+ "NEG",
+};
+
+static const char *logic_threshold[] = {
+ "USER",
+ "TTL",
+ "ECL",
+ "CMOS",
+};
+
+static const char *trigger_sources[] = {
+ "CHAN1", "CHAN2",
+ "LINE", "EXT", "NONE",
+ "DIG0", "DIG1", "DIG2", "DIG3", "DIG4", "DIG5", "DIG6", "DIG7", "DIG8", "DIG9", "DIG10", "DIG11", "DIG12", "DIG13", "DIG14", "DIG15",
+};
+
+/* This is not currently used */
+static const char *trigger_mode[] = {
+ "EDGE",
+ "GLIT",
+ "PATT",
+ "CAN",
+ "DUR",
+ "IIC",
+ "LIN",
+ "SEQ",
+ "SPI",
+ "TV",
+ "USB",
+};
+
+static const uint64_t scope_timebases[][2] = {
+ /* nanoseconds */
+ { 5, 1000000000 },
+ { 10, 1000000000 },
+ { 20, 1000000000 },
+ { 50, 1000000000 },
+ { 100, 1000000000 },
+ { 500, 1000000000 },
+ /* microseconds */
+ { 1, 1000000 },
+ { 2, 1000000 },
+ { 5, 1000000 },
+ { 10, 1000000 },
+ { 20, 1000000 },
+ { 50, 1000000 },
+ { 100, 1000000 },
+ { 200, 1000000 },
+ { 500, 1000000 },
+ /* milliseconds */
+ { 1, 1000 },
+ { 2, 1000 },
+ { 5, 1000 },
+ { 10, 1000 },
+ { 20, 1000 },
+ { 50, 1000 },
+ { 100, 1000 },
+ { 200, 1000 },
+ { 500, 1000 },
+ /* seconds */
+ { 1, 1 },
+ { 2, 1 },
+ { 5, 1 },
+ { 10, 1 },
+ { 20, 1 },
+ { 50, 1 },
+};
+
+static const uint64_t vdivs[][2] = {
+ /* millivolts */
+ { 1, 1000 },
+ { 2, 1000 },
+ { 5, 1000 },
+ { 10, 1000 },
+ { 20, 1000 },
+ { 50, 1000 },
+ { 100, 1000 },
+ { 200, 1000 },
+ { 500, 1000 },
+ /* volts */
+ { 1, 1 },
+ { 2, 1 },
+ { 5, 1 },
+ { 10, 1 },
+ { 20, 1 },
+ { 50, 1 },
+ { 100, 1 },
+};
+
+static const char *scope_analog_channel_names[] = {
+ "CH1", "CH2",
+};
+
+static const char *scope_digital_channel_names[] = {
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15",
+};
+
+static struct scope_config scope_models[] = {
+ {
+ /* Agilent 54621D/54622D Models only differ in Bandwidth; everything else should be the same*/
+ .name = {"54621D", "54622D", NULL},
+ .analog_channels = 2,
+ .digital_channels = 16,
+
+ .analog_names = &scope_analog_channel_names,
+ .digital_names = &scope_digital_channel_names,
+
+ .devopts = &devopts,
+ .num_devopts = ARRAY_SIZE(devopts),
+
+ .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),
+
+ .digital_pods = 2,
+
+ .coupling_options = &coupling_options,
+ .num_coupling_options = ARRAY_SIZE(coupling_options),
+
+ .logic_threshold = &logic_threshold,
+ .num_logic_threshold = ARRAY_SIZE(logic_threshold),
+ .logic_threshold_for_pod = TRUE,
+
+ .trigger_sources = &trigger_sources,
+ .num_trigger_sources = ARRAY_SIZE(trigger_sources),
+
+ .trigger_slopes = &scope_trigger_slopes,
+ .num_trigger_slopes = ARRAY_SIZE(scope_trigger_slopes),
+
+ .timebases = &scope_timebases,
+ .num_timebases = ARRAY_SIZE(scope_timebases),
+
+ .vdivs = &vdivs,
+ .num_vdivs = ARRAY_SIZE(vdivs),
+
+ .num_xdivs = 10,
+ .num_ydivs = 8,
+
+ .scpi_dialect = &agilent_scpi_dialect,
+ },
+ //ToDo: Implement other scope models
+};
+
+SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
+{
+ const struct sr_dev_inst *sdi;
+ struct dev_context *devc;
+
+ (void)fd;
+
+ sdi = cb_data;
+ if (!sdi)
+ return TRUE;
+
+ devc = sdi->priv;
+ if (!devc)
+ return TRUE;
+
+ if (revents == G_IO_IN) {
+ /* TODO */
+ }
+
+ return TRUE;
+}
+
+SR_PRIV int agilent_54621d_update_sample_rate(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ struct scope_state *state;
+ const struct scope_config *config;
+ uint64_t tmp_int;
+
+ devc = sdi->priv;
+ config = devc->model_config;
+ state = devc->model_state;
+
+ if (sr_scpi_get_int(sdi->conn,
+ (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE],
+ &tmp_int) != SR_OK)
+ return SR_ERR;
+
+ state->sample_rate = tmp_int;
+
+
+
+ return SR_OK;
+}
+
+SR_PRIV int agilent_54621d_init_device(struct sr_dev_inst *sdi)
+{
+ int model_index;
+ unsigned int i, j, group;
+ struct sr_channel *ch;
+ struct dev_context *devc;
+ const char *cg_name;
+ int ret;
+
+ devc = sdi->priv;
+ model_index = -1;
+
+ /* find model */
+ for(i = 0; i < ARRAY_SIZE(scope_models); i++) {
+ for(j = 0; scope_models[i].name[j]; j++) {
+ if(!strcmp(sdi->model, scope_models[i].name[j])) {
+ model_index = i;
+ }
+ }
+ if(model_index != -1)
+ break;
+ }
+
+ if(model_index == -1){
+ sr_dbg("Unsupported device.");
+ return SR_ERR_NA;
+ }
+
+ devc->analog_groups = g_malloc0(sizeof(struct sr_channel_group*) *scope_models[model_index].analog_channels);
+ devc->digital_groups = g_malloc0(sizeof(struct sr_channel_group*) *scope_models[model_index].digital_pods);
+ if(!devc->analog_groups || !devc->digital_groups){
+ g_free(devc->analog_groups);
+ g_free(devc->digital_groups);
+ return SR_ERR_MALLOC;
+ }
+
+ /* Add analog channels. */
+ for (i = 0; i < scope_models[model_index].analog_channels; i++) {
+ ch = sr_channel_new(sdi, i, SR_CHANNEL_ANALOG, TRUE,
+ (*scope_models[model_index].analog_names)[i]);
+
+ cg_name = (*scope_models[model_index].analog_names)[i];
+ devc->analog_groups[i] = sr_channel_group_new(sdi, cg_name, NULL);
+ devc->analog_groups[i]->channels = g_slist_append(NULL, ch);
+ }
+
+ /* Add digital channel groups. */
+ ret = SR_OK;
+ for (i = 0; i < scope_models[model_index].digital_pods; i++) {
+ devc->digital_groups[i] = sr_channel_group_new(sdi, NULL, NULL);
+ if (!devc->digital_groups[i]) {
+ ret = SR_ERR_MALLOC;
+ break;
+ }
+ devc->digital_groups[i]->name = g_strdup_printf("POD%d", i + 1);
+ }
+ if (ret != SR_OK)
+ return ret;
+
+ /* Add digital channels. */
+ for (i = 0; i < scope_models[model_index].digital_channels; i++) {
+ ch = sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE,
+ (*scope_models[model_index].digital_names)[i]);
+
+ group = i / DIGITAL_CHANNELS_PER_POD;
+ devc->digital_groups[group]->channels = g_slist_append(
+ devc->digital_groups[group]->channels, ch);
+ }
+
+ devc->model_config = &scope_models[model_index];
+ devc->samples_limit = 2000;
+ devc->frame_limit = 0;
+
+ if (!(devc->model_state = scope_state_new(devc->model_config)))
+ return SR_ERR_MALLOC;
+
+
+ return SR_OK;
+}
+
+static struct scope_state *scope_state_new(const struct scope_config *config) {
+ struct scope_state *state;
+
+ state = g_malloc0(sizeof(struct scope_state));
+ state->analog_channels = g_malloc0_n(config->analog_channels, sizeof(struct analog_channel_state));
+ state->digital_channels = g_malloc0_n(config->digital_channels, sizeof(gboolean) * MAX_DIGITAL_CHANNEL_COUNT); //ToDo: Why ony one bool size for the digital channel state? Shouldn't it be 1bool per channel?
+ state->digital_pods = g_malloc0_n(config->digital_pods, sizeof(struct digital_pod_state));
+
+ return state;
+}
+
+SR_PRIV int agilent_54621d_scope_state_get(struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ struct scope_state *state;
+ const struct scope_config *config;
+ float tmp_float;
+ unsigned int i;
+ char *tmp_str;
+
+ devc = sdi->priv;
+ config = devc->model_config;
+ state = devc->model_state;
+
+ sr_info("Fetching scope state");
+
+ //get analog channel state
+ if (analog_channel_state_get(sdi, config, state) != SR_OK)
+ return SR_ERR;
+
+ //get digital channel state
+ if (digital_channel_state_get(sdi, config, state) != SR_OK)
+ return SR_ERR;
+
+ //get timebase
+ if (sr_scpi_get_string(sdi->conn,
+ (*config->scpi_dialect)[SCPI_CMD_GET_TIMEBASE],
+ &tmp_str) != SR_OK)
+ return SR_ERR;
+
+ if (array_float_get(tmp_str, ARRAY_AND_SIZE(scope_timebases), &i) != SR_OK) {
+ g_free(tmp_str);
+ sr_err("Could not determine array index for time base.");
+ return SR_ERR;
+ }
+ g_free(tmp_str);
+
+ state->timebase = i;
+
+ //get trigger horizontal position
+ if(sr_scpi_get_float(sdi->conn, (*config->scpi_dialect)[SCPI_CMD_GET_HORIZ_TRIGGERPOS], &tmp_float) != SR_OK)
+ return SR_ERR;
+
+ state->horiz_triggerpos = tmp_float /
+ (((double) (*config->timebases)[state->timebase][0] /
+ (*config->timebases)[state->timebase][1]) * config->num_xdivs);
+ state->horiz_triggerpos -= 0.5;
+ state->horiz_triggerpos *= -1;
+ //ToDo: This might be dependent on time ref setting
+
+ if (scope_state_get_array_option(sdi->conn, (*config->scpi_dialect)[SCPI_CMD_GET_TRIGGER_SOURCE], config->trigger_sources, config->num_trigger_sources, &state->trigger_source) != SR_OK)
+ return SR_ERR;
+
+ if (scope_state_get_array_option(sdi->conn, (*config->scpi_dialect)[SCPI_CMD_GET_TRIGGER_SLOPE], config->trigger_slopes, config->num_trigger_slopes, &state->trigger_slope) != SR_OK)
+ return SR_ERR;
+
+ //ToDo: get trigger pattern
+ //documentation for reading the trigger pattern is a little wonky so I need to test how this is done
+ strncpy(state->trigger_pattern, "0000000000000000000000", MAX_ANALOG_CHANNEL_COUNT + MAX_DIGITAL_CHANNEL_COUNT);
+
+
+ //ToDo: get current resolution
+ //Default resolution is 8bit. aquiring at 8 bit also can increase transfer speed, since only a byte of data per point has to be transmitted
+ //Resolution is a function of sweep speed and number of averages
+ //Resolution > 8bit if acq mode == avg && (timebase >= 5us/div || num_avg>1)
+ state->high_resolution = FALSE;
+
+
+ //get peak detection
+ if (sr_scpi_get_string(sdi->conn,
+ (*config->scpi_dialect)[SCPI_CMD_GET_PEAK_DETECTION],
+ &tmp_str) != SR_OK)
+ return SR_ERR;
+ if (!strcmp("PEAK", tmp_str))
+ state->peak_detection = TRUE;
+ else
+ state->peak_detection = FALSE;
+ g_free(tmp_str);
+
+ if(agilent_54621d_update_sample_rate(sdi) != SR_OK)
+ return SR_ERR;
+
+ sr_info("Fetching finished.");
+
+ scope_state_dump(config, state);
+
+ return SR_OK;
+}
+
+static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi, const char *command, const char *(*array)[], unsigned int n, int *result)
+{
+ char *tmp;
+ int idx;
+
+ if (sr_scpi_get_string(scpi, command, &tmp) != SR_OK)
+ return SR_ERR;
+
+ if ((idx = std_str_idx_s(tmp, *array, n)) < 0) {
+ g_free(tmp);
+ return SR_ERR_ARG;
+ }
+
+ *result = idx;
+
+ g_free(tmp);
+
+ return SR_OK;
+}
+
+
+/*
+*This function is a helper function to output the scope configuration to the info log
+*
+*
+*
+*/
+static void scope_state_dump(const struct scope_config *config, struct scope_state *state)
+{
+ unsigned int i;
+ char *tmp;
+
+ for (i = 0; i < config->analog_channels; i++) {
+ tmp = sr_voltage_string((*config->vdivs)[state->analog_channels[i].vdiv][0],
+ (*config->vdivs)[state->analog_channels[i].vdiv][1]);
+ sr_info("State of analog channel %d -> %s : %s (coupling) %s (vdiv) %2.2e (offset)",
+ i + 1, state->analog_channels[i].state ? "On" : "Off",
+ (*config->coupling_options)[state->analog_channels[i].coupling],
+ tmp, state->analog_channels[i].vertical_offset);
+ }
+
+ for (i = 0; i < config->digital_channels; i++) {
+ sr_info("State of digital channel %d -> %s", i,
+ state->digital_channels[i] ? "On" : "Off");
+ }
+
+ for (i = 0; i < config->digital_pods; i++) {
+ if (!strncmp("USER", (*config->logic_threshold)[state->digital_pods[i].threshold], 4) ||
+ !strcmp("MAN", (*config->logic_threshold)[state->digital_pods[i].threshold]))
+ sr_info("State of digital POD %d -> %s : %E (threshold)", i + 1,
+ state->digital_pods[i].state ? "On" : "Off",
+ state->digital_pods[i].user_threshold);
+ else
+ sr_info("State of digital POD %d -> %s : %s (threshold)", i + 1,
+ state->digital_pods[i].state ? "On" : "Off",
+ (*config->logic_threshold)[state->digital_pods[i].threshold]);
+ }
+
+ tmp = sr_period_string((*config->timebases)[state->timebase][0],
+ (*config->timebases)[state->timebase][1]);
+ sr_info("Current timebase: %s", tmp);
+ g_free(tmp);
+
+ tmp = sr_samplerate_string(state->sample_rate);
+ sr_info("Current samplerate: %s", tmp);
+ g_free(tmp);
+
+ if (!strcmp("PATT", (*config->trigger_sources)[state->trigger_source]))
+ sr_info("Current trigger: %s (pattern), %.2f (offset)",
+ state->trigger_pattern,
+ state->horiz_triggerpos);
+ else // Edge (slope) trigger
+ sr_info("Current trigger: %s (source), %s (slope) %.2f (offset)",
+ (*config->trigger_sources)[state->trigger_source],
+ (*config->trigger_slopes)[state->trigger_slope],
+ state->horiz_triggerpos);
+}
+
+/**
+ * This function takes a value of the form "2.000E-03" and returns the index
+ * of an array where a matching pair was found.
+ *
+ * @param value The string to be parsed.
+ * @param array The array of s/f pairs.
+ * @param array_len The number of pairs in the array.
+ * @param result The index at which a matching pair was found.
+ *
+ * @return SR_ERR on any parsing error, SR_OK otherwise.
+ */
+static int array_float_get(gchar *value, const uint64_t array[][2], int array_len, unsigned int *result)
+{
+ struct sr_rational rval;
+ struct sr_rational aval;
+
+ if (sr_parse_rational(value, &rval) != SR_OK)
+ return SR_ERR;
+
+ for (int i = 0; i < array_len; i++) {
+ sr_rational_set(&aval, array[i][0], array[i][1]);
+ if (sr_rational_eq(&rval, &aval)) {
+ *result = i;
+ return SR_OK;
+ }
+ }
+
+ return SR_ERR;
+}
+
+static struct sr_channel *get_channel_by_index_and_type(GSList *channel_lhead,
+ int index, int type)
+{
+ while (channel_lhead) {
+ struct sr_channel *ch = channel_lhead->data;
+ if (ch->index == index && ch->type == type)
+ return ch;
+
+ channel_lhead = channel_lhead->next;
+ }
+
+ return 0;
+}
+
+static int analog_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state)
+{
+ unsigned int i, j;
+ char command[MAX_COMMAND_SIZE];
+ char *tmp_str;
+ struct sr_channel *ch;
+ struct sr_scpi_dev_inst *scpi = sdi->conn;
+
+ for(i = 0; i < config->analog_channels; i++){
+ //get channel enabled (visible)
+ g_snprintf(command, sizeof(command), (*config->scpi_dialect)[SCPI_CMD_GET_ANALOG_CHAN_STATE], i+1);
+
+ if(sr_scpi_get_bool(scpi, command, &state->analog_channels[i].state) != SR_OK)
+ return SR_ERR;
+
+ ch = get_channel_by_index_and_type(sdi->channels, i, SR_CHANNEL_ANALOG);
+ if(ch)
+ ch->enabled = state->analog_channels[i].state;
+
+ //get vertical scale (v/div)
+ g_snprintf(command, sizeof(command), (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_SCALE], i+1);
+
+ if(sr_scpi_get_string(scpi, command, &tmp_str) != SR_OK)
+ return SR_ERR;
+
+ if(array_float_get(tmp_str, *(config->vdivs), config->num_vdivs, &j) != SR_OK){
+ g_free(tmp_str);
+ sr_err("could not determine array index for vertical div scale.");
+ return SR_ERR;
+ }
+
+ g_free(tmp_str);
+ state->analog_channels[i].vdiv = j;
+
+ //Get vertical offset
+ g_snprintf(command, sizeof(command),
+ (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_OFFSET],
+ i + 1);
+
+ if (sr_scpi_get_float(scpi, command,
+ &state->analog_channels[i].vertical_offset) != SR_OK)
+ return SR_ERR;
+
+ //get coupling
+ g_snprintf(command, sizeof(command),
+ (*config->scpi_dialect)[SCPI_CMD_GET_COUPLING],
+ i + 1);
+
+ if (scope_state_get_array_option(scpi, command, config->coupling_options,
+ config->num_coupling_options,
+ &state->analog_channels[i].coupling) != SR_OK)
+ return SR_ERR;
+
+ //get Unit (Amp/Volt)
+ g_snprintf(command, sizeof(command),
+ (*config->scpi_dialect)[SCPI_CMD_GET_PROBE_UNIT],
+ i + 1);
+
+ if (sr_scpi_get_string(scpi, command, &tmp_str) != SR_OK)
+ return SR_ERR;
+
+ if (tmp_str[0] == 'A')
+ state->analog_channels[i].probe_unit = 'A';
+ else
+ state->analog_channels[i].probe_unit = 'V';
+ g_free(tmp_str);
+ }
+
+ return SR_OK;
+}
+
+static int digital_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state)
+{
+ unsigned int i, user_index;
+ char command[MAX_COMMAND_SIZE];
+ struct sr_channel *ch;
+ struct sr_scpi_dev_inst *scpi = sdi->conn;
+
+ //get enabled channels
+ for (i = 0; i < config->digital_channels; i++) {
+ g_snprintf(command, sizeof(command),
+ (*config->scpi_dialect)[SCPI_CMD_GET_DIG_CHAN_STATE],
+ i);
+
+ if (sr_scpi_get_bool(scpi, command,
+ &state->digital_channels[i]) != SR_OK)
+ return SR_ERR;
+
+ ch = get_channel_by_index_and_type(sdi->channels, i, SR_CHANNEL_LOGIC);
+ if (ch)
+ ch->enabled = state->digital_channels[i];
+ }
+
+ for (user_index = 0; user_index < ARRAY_SIZE(logic_threshold); user_index++){
+ if(!strcmp(logic_threshold[i], LOGIC_GET_THRESHOLD_SETTING))
+ break;
+ }
+
+ for (i = 0; i < config->digital_pods; i++){
+ //get enabled pods
+ 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].state) != SR_OK)
+ return SR_ERR;
+
+ //get logic threshold
+ //the device driver will allways report logic threshold to be "USER" with the currently set actual level saved as user level, since the device only reports current voltage but not the current setting
+ state->digital_pods[i].threshold = user_index;
+ g_snprintf(command, sizeof(command), (*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_THRESHOLD], i+1);
+
+ if(sr_scpi_get_float(scpi, command, &state->digital_pods[i].user_threshold) != SR_OK)
+ return SR_ERR;
+
+ }
+ return SR_OK;
+}
+
diff --git a/src/hardware/agilent-54621d/protocol.h b/src/hardware/agilent-54621d/protocol.h
new file mode 100644
index 000000000..abf64b8a8
--- /dev/null
+++ b/src/hardware/agilent-54621d/protocol.h
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2022 Daniel <1824222@stud.hs-mannheim.de>
+ *
+ * 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 .
+ */
+
+#ifndef LIBSIGROK_HARDWARE_AGILENT_54621D_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_AGILENT_54621D_PROTOCOL_H
+
+#include
+#include
+#include
+#include
+#include "libsigrok-internal.h"
+#include "scpi.h"
+
+#define LOG_PREFIX "agilent-54621d"
+#define MAX_COMMAND_SIZE 128
+
+#define DIGITAL_CHANNELS_PER_POD 8
+#define MAX_INSTRUMENT_VERSIONS 10
+#define MAX_ANALOG_CHANNEL_COUNT 4
+#define MAX_DIGITAL_CHANNEL_COUNT 16
+#define MAX_DIGITAL_POD_COUNT 2
+#define MAX_DIGITAL_GROUP_COUNT 2
+
+
+struct scope_config {
+ const char *name[MAX_INSTRUMENT_VERSIONS];
+ const uint8_t analog_channels;
+ const uint8_t digital_channels;
+ uint8_t digital_pods;
+
+ const char *(*analog_names)[];
+ const char *(*digital_names)[];
+
+ const uint32_t (*devopts)[];
+ const uint8_t num_devopts;
+
+ 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 gboolean logic_threshold_for_pod;
+
+ const char *(*trigger_sources)[];
+ const uint8_t num_trigger_sources;
+
+ const char *(*trigger_slopes)[];
+ const uint8_t num_trigger_slopes;
+
+ const uint64_t (*timebases)[][2];
+ const uint8_t num_timebases;
+
+ const uint64_t (*vdivs)[][2];
+ const uint8_t num_vdivs;
+
+ unsigned int num_xdivs;
+ const unsigned int num_ydivs;
+
+ const char *(*scpi_dialect)[];
+};
+
+struct analog_channel_state {
+ int coupling;
+
+ int vdiv;
+ float vertical_offset;
+
+ gboolean 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;
+ struct digital_pod_state *digital_pods;
+
+ int timebase;
+ float horiz_triggerpos;
+
+ int trigger_source;
+ int trigger_slope;
+ char trigger_pattern[MAX_ANALOG_CHANNEL_COUNT + MAX_DIGITAL_CHANNEL_COUNT + 1];
+
+ gboolean high_resolution;
+ gboolean peak_detection;
+
+ uint64_t sample_rate;
+};
+
+struct dev_context {
+ const void *model_config;
+ void *model_state;
+
+ /* Device properties */
+ const float minTimebase;
+ const float maxTimebase;
+
+ struct sr_channel_group **analog_groups;
+ struct sr_channel_group **digital_groups;
+
+ GSList *enabled_channels;
+ GSList *current_channel;
+ uint64_t num_samples;
+ uint64_t num_frames;
+
+ uint64_t samples_limit;
+ uint64_t frame_limit;
+
+ size_t pod_count;
+ GByteArray *logic_data;
+};
+
+SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int agilent_54621d_init_device(struct sr_dev_inst *sdi);
+SR_PRIV int agilent_54621d_scope_state_get(struct sr_dev_inst *sdi);
+SR_PRIV int agilent_54621d_update_sample_rate(const struct sr_dev_inst *sdi);
+static struct scope_state *scope_state_new(const struct scope_config *config);
+static int analog_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
+static int digital_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
+static int array_float_get(gchar *value, const uint64_t array[][2], int array_len, unsigned int *result);
+static void scope_state_dump(const struct scope_config *config, struct scope_state *state);
+static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi, const char *command, const char *(*array)[], unsigned int n, int *result);
+
+#endif
diff --git a/src/scpi/scpi.c b/src/scpi/scpi.c
index be829af4b..6adcb0df6 100644
--- a/src/scpi/scpi.c
+++ b/src/scpi/scpi.c
@@ -57,6 +57,7 @@ static int parse_strict_bool(const char *str, gboolean *ret)
return SR_ERR_ARG;
if (!g_strcmp0(str, "1") ||
+ !g_strcmp0(str, "+1") ||
!g_ascii_strncasecmp(str, "y", 1) ||
!g_ascii_strncasecmp(str, "t", 1) ||
!g_ascii_strncasecmp(str, "yes", 3) ||
From 57cd25998260eeec52efd339b6a08081ea81f92d Mon Sep 17 00:00:00 2001
From: Daniel <1824222@stud.hs-mannheim.de>
Date: Sun, 15 Jan 2023 13:57:10 +0100
Subject: [PATCH 2/9] Implemented data download. Digital channels are not yet
working properly
---
src/hardware/agilent-54621d/api.c | 368 +++++++++++++++++++++----
src/hardware/agilent-54621d/protocol.c | 306 ++++++++++++++++++--
src/hardware/agilent-54621d/protocol.h | 32 ++-
3 files changed, 625 insertions(+), 81 deletions(-)
diff --git a/src/hardware/agilent-54621d/api.c b/src/hardware/agilent-54621d/api.c
index 9ef63f6a1..9bc56bfbc 100644
--- a/src/hardware/agilent-54621d/api.c
+++ b/src/hardware/agilent-54621d/api.c
@@ -20,6 +20,10 @@
#include
#include "protocol.h"
#include "scpi.h"
+#include
+
+#define WAIT_FOR_CAPTURE_COMPLETE_RETRIES 100
+#define WAIT_FOR_CAPTURE_COMPLETE_DELAY (100*1000)
static struct sr_dev_driver agilent_54621d_driver_info;
@@ -44,6 +48,49 @@ enum {
CG_DIGITAL,
};
+//Do not change order
+static const char *data_sources[] = {
+ "Live",
+ "Memory",
+};
+
+static const char *data_channels[] = {
+ "CHAN1",
+ "CHAN2",
+ "POD1",
+ "POD2",
+};
+
+static const uint64_t samplerates[] = {
+ SR_HZ(1),
+ SR_MHZ(200),
+ SR_HZ(1),
+};
+
+static const uint64_t samplerates_literal[] = {
+ SR_KHZ(2),
+ SR_KHZ(4),
+ SR_KHZ(5),
+ SR_KHZ(10),
+ SR_KHZ(20),
+ SR_KHZ(40),
+ SR_KHZ(50),
+ SR_KHZ(100),
+ SR_KHZ(200),
+ SR_KHZ(400),
+ SR_KHZ(500),
+ SR_MHZ(1),
+ SR_MHZ(2),
+ SR_MHZ(4),
+ SR_MHZ(5),
+ SR_MHZ(10),
+ SR_MHZ(20),
+ SR_MHZ(25),
+ SR_MHZ(50), //Can appear on device
+ SR_MHZ(100), //Can appear on device
+ SR_MHZ(200), //Can appear on device
+};
+
static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
{
struct sr_dev_inst *sdi;
@@ -225,7 +272,7 @@ static int config_get(uint32_t key, GVariant **data,
*data = g_variant_new_string((*model->coupling_options)[state->analog_channels[idx].coupling]);
break;
case SR_CONF_SAMPLERATE:
- *data = g_variant_new_uint64(state->sample_rate);
+ *data = g_variant_new_uint64(devc->sample_rate_limit); //state->sample_rate
break;
case SR_CONF_LOGIC_THRESHOLD:
if (!cg)
@@ -252,6 +299,12 @@ static int config_get(uint32_t key, GVariant **data,
case SR_CONF_LIMIT_SAMPLES:
*data = g_variant_new_uint64(devc->samples_limit);
break;
+ case SR_CONF_DATA_SOURCE:
+ if (devc->data_source == DATA_SOURCE_LIVE)
+ *data = g_variant_new_string("Live");
+ else if (devc->data_source == DATA_SOURCE_MEMORY)
+ *data = g_variant_new_string("Memory");
+ break;
//ToDo: Check if all options are implemented
default:
sr_err("could not find requested parameter: %d", key);
@@ -272,6 +325,7 @@ static int config_set(uint32_t key, GVariant *data,
struct scope_state *state;
double tmp_d, tmp_d2;
gboolean update_sample_rate, tmp_bool;
+ int tmp_int;
if (!sdi)
return SR_ERR_ARG;
@@ -286,8 +340,24 @@ static int config_set(uint32_t key, GVariant *data,
update_sample_rate = FALSE;
switch (key) {
+ case SR_CONF_SAMPLERATE:
+ if(state->sample_rate < g_variant_get_uint64(data)){
+ devc->sample_rate_limit = state->sample_rate;
+ ret = SR_OK;
+ } else {
+ devc->sample_rate_limit = g_variant_get_uint64(data);
+ ret = SR_OK;
+ }
+ break;
case SR_CONF_LIMIT_SAMPLES:
- devc->samples_limit = g_variant_get_uint64(data);
+ tmp_int = g_variant_get_uint64(data);
+ tmp_d = (double)tmp_int/devc->sample_rate_limit; //total time to be transmitted
+ tmp_d2 = 10*((float) (*model->timebases)[state->timebase][0] / (*model->timebases)[state->timebase][1]); //total time shown in display
+ if(tmp_d > tmp_d2){ //dont allow to transmit more data than shown in the main view. One could zoom out to increase the amount of data shown, but implementing that would probably be a bitch so this driver wont allow to download more data than shown in main view
+ devc->samples_limit = tmp_d2*devc->sample_rate_limit;
+ } else {
+ devc->samples_limit = g_variant_get_uint64(data);
+ }
ret = SR_OK;
break;
case SR_CONF_VDIV:
@@ -458,52 +528,20 @@ static int config_set(uint32_t key, GVariant *data,
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);
- /* Check if the threshold command is based on the POD or digital channel index. */
- if (model->logic_threshold_for_pod)
- idx = j + 1;
- else
- idx = j * DIGITAL_CHANNELS_PER_POD;
- /* Try to support different dialects exhaustively. */
- for (i = 0; i < model->num_logic_threshold; i++) {
- if (!strcmp("USER2", (*model->logic_threshold)[i])) {
- g_snprintf(command, sizeof(command),
- (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
- idx, 2, float_str); /* USER2 */
- g_snprintf(command2, sizeof(command2),
- (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
- idx, "USER2");
- break;
- }
- if (!strcmp("USER", (*model->logic_threshold)[i])) {
- g_snprintf(command, sizeof(command),
- (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
- idx, float_str);
- g_snprintf(command2, sizeof(command2),
- (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
- idx, "USER");
- break;
- }
- if (!strcmp("MAN", (*model->logic_threshold)[i])) {
- g_snprintf(command, sizeof(command),
- (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
- idx, float_str);
- g_snprintf(command2, sizeof(command2),
- (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
- idx, "MAN");
- break;
- }
- }
- if (sr_scpi_send(sdi->conn, command) != SR_OK ||
- sr_scpi_get_opc(sdi->conn) != SR_OK)
- return SR_ERR;
- if (sr_scpi_send(sdi->conn, command2) != SR_OK ||
- sr_scpi_get_opc(sdi->conn) != SR_OK)
+ //ToDo: implement logic
+ ret = SR_OK;
+ break;
+ case SR_CONF_DATA_SOURCE:
+ tmp_str = g_variant_get_string(data, NULL);
+ sr_dbg("Setting data source to: '%s'", tmp_str);
+ if(!strcmp(tmp_str, "Live"))
+ devc->data_source = DATA_SOURCE_LIVE;
+ else if(!strcmp(tmp_str, "Memory"))
+ devc->data_source = DATA_SOURCE_MEMORY;
+ else {
+ sr_err("Unknown data source: '%s'", tmp_str);
return SR_ERR;
- state->digital_pods[j].user_threshold = tmp_d;
+ }
ret = SR_OK;
break;
default:
@@ -536,6 +574,9 @@ static int config_list(uint32_t key, GVariant **data,
ret = SR_OK;
switch (key) {
+ case SR_CONF_SAMPLERATE:
+ *data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
+ break;
case SR_CONF_SCAN_OPTIONS:
*data = std_gvar_array_u32(ARRAY_AND_SIZE(scanopts));
break;
@@ -589,6 +630,9 @@ static int config_list(uint32_t key, GVariant **data,
return SR_ERR_ARG;
*data = g_variant_new_strv(*model->logic_threshold, model->num_logic_threshold);
break;
+ case SR_CONF_DATA_SOURCE:
+ *data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources));
+ break;
/* TODO Check if all relevant option are present here */
default:
sr_info("Trying to query for config list for:");
@@ -607,9 +651,22 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct sr_scpi_dev_inst *scpi;
struct scope_state *state;
const struct scope_config *model;
- int ret;
+ int ret, i;
char *cmd;
gboolean state_changed;
+ volatile int tmp_int;
+ gboolean acq_complete;
+ gboolean tmp_bool;
+ char command[MAX_COMMAND_SIZE];
+ float xinc;
+ int points;
+ char *tmp_string;
+ float tmp_float;
+ struct analog_channel_transfer_info *encoding;
+ int xref;
+ gboolean channel_available;
+ gboolean digital_added[MAX_DIGITAL_GROUP_COUNT];
+ size_t group, pod_count;
scpi = sdi->conn;
devc = sdi->priv;
@@ -619,9 +676,14 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
devc->num_samples = 0;
devc->num_frames = 0;
+ //reset to empty
+ for (group = 0; group < ARRAY_SIZE(digital_added); group++)
+ digital_added[group] = FALSE;
+ g_slist_free(devc->enabled_channels);
devc->enabled_channels = NULL;
state_changed = FALSE;
+ pod_count = 0;
for (l = sdi->channels; l; l = l->next) {
ch = l->data;
sr_dbg("initializing channel %s", ch->name);
@@ -637,7 +699,12 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
state_changed = TRUE;
}
} else if (ch->type == SR_CHANNEL_LOGIC) {
- devc->enabled_channels = g_slist_append(devc->enabled_channels, ch);
+ group = ch->index / DIGITAL_CHANNELS_PER_POD;
+ if(ch->enabled && !digital_added[group]){ //Only add a single channel per pod
+ devc->enabled_channels = g_slist_append(devc->enabled_channels, ch);
+ digital_added[group] = TRUE;
+ pod_count++;
+ }
//Enable/disable channel if neccessary
if(ch->enabled != state->digital_channels[ch->index]) {
if( sr_scpi_send(scpi, (*model->scpi_dialect)[SCPI_CMD_SET_DIG_CHAN_STATE], ch->index, ch->enabled ? "ON" : "OFF") != SR_OK ||
@@ -648,15 +715,201 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
}
}
}
+ devc->current_channel = devc->enabled_channels;
+ devc->pod_count = pod_count;
+
+ //ToDo: this is a hacky workaround to get what channel groups need to be downloaded. Ther surely is a better way to do this.
+ //ToDo2: Is this even used?
+ devc->channels_to_download = NULL;
+ for(i = 0; ichannels_to_download = g_slist_append(devc->channels_to_download, data_channels[i]);
+ }
//Sample rate needs to be updated if channels have been changed, since in some channel configurations sample rate is reduced
- if(state_changed)
+ if(TRUE){
+ sr_scpi_send(scpi, ":RUN"); //Device needs to run in order to get the correct sample rate
+ if(sr_scpi_get_opc(scpi) != SR_OK){
+ sr_err("Couldnt set device to running");
+ return SR_ERR;
+ }
if(agilent_54621d_update_sample_rate(sdi) != SR_OK)
return SR_ERR;
+ }
+
+ if(devc->data_source == DATA_SOURCE_LIVE){
+ sr_scpi_send(scpi, ":SING");
+ acq_complete = FALSE;
+ for(i = 0; i device is stopped. This should be the case once the acquisition is complete
+ acq_complete = TRUE;
+ sr_dbg("Acquisition complete");
+ break;
+ }
+ g_usleep(WAIT_FOR_CAPTURE_COMPLETE_DELAY);
+ if(agilent_54621d_update_sample_rate(sdi) != SR_OK)
+ return SR_ERR;
+ }
+ if(!acq_complete){
+ sr_err("Capture Timed out");
+ return SR_ERR;
+ }
+ } else if (devc->data_source == DATA_SOURCE_MEMORY) {
+ g_snprintf(command, sizeof(command), ":WAV:SOUR %s", devc->channels_to_download[0]);
+ sr_scpi_send(scpi, command);
+ sr_scpi_get_int(scpi, ":WAV:POIN? MAX", &tmp_int);
+ if(tmp_int <= 0){
+ sr_err("No waveform in Memory");
+ return SR_OK;
+ }
+ } else {
+ sr_err("Unknown datasource");
+ return SR_ERR;
+ }
+
+ sr_dbg("determine steps to download data");
+
+ /*
+ * Downloading data is done in a quite manual way to speed up downloading. The device only allows downloading upto 2k points from the view-buffer, or the complete captured waveform (~1m points)
+ * The logic is, that if we want less than the complete waveform we can switch to window view, calculate the settings to have the window show exactly 2k points of the wv, and then transfer these 2k points.
+ * Then we can move the window delay and download the next 2k points. We can repeat this until we have the desired amount of points.
+ * This is also how the scope transfers the full waveform, however transfering the full wavefrom cannot be interrupted, so the manual approach is better
+ * We save the number of samples already downloaded in devc->num_samples, and the samples themselves in devc->buffer until all data for a channel is ready
+ */
+
+ //Reset parameters
+ devc->num_samples = 0;
+ devc->num_blocks_downloaded = 0;
+ devc->buffer = g_malloc0(sizeof(char) * devc->samples_limit);
+ devc->headerSent = FALSE;
+
+ //set waveform source channel to the first channel to be downloaded
+ ch = (struct sr_channel *)devc->enabled_channels->data;
+ if(ch->type == SR_CHANNEL_LOGIC){
+ group = ch->index/DIGITAL_CHANNELS_PER_POD+1;
+ g_snprintf(command, sizeof(command), ":WAV:SOUR POD%d", group);
+ } else {
+ g_snprintf(command, sizeof(command), ":WAV:SOUR %s", ch->name);
+ }
+ sr_scpi_send(scpi, command);
+
+ //get required data for calculations
+ sr_scpi_send(scpi, ":TIM:MODE MAIN;:WAV:POIN MAX");
+ sr_scpi_send(scpi, ":WAV:UNS 0");
+ g_usleep(300000); //Apparently the device needs a little time to do the wav:sour and tim:mode setup before requesting wav:poin? max. waiting 30ms should be enough
+ if(sr_scpi_get_int(scpi, ":WAV:POIN? MAX", &points) != SR_OK){
+ sr_err("Couldn't get max Points");
+ return SR_ERR;
+ }
+ if(sr_scpi_get_float(scpi, ":WAV:XINC?", &xinc) != SR_OK){ //ToDo: is currently unneccessarysince the value needs to be updated after zooming
+ sr_err("Couldn't get x inc");
+ return SR_ERR;
+ }
+ if(sr_scpi_get_string(scpi, ":TIM:REF?", &tmp_string) != SR_OK){
+ sr_err("Couldn't get time ref");
+ return SR_ERR;
+ }
+ if(sr_scpi_get_float(scpi, ":TIM:SCAL?", &tmp_float) != SR_OK){
+ sr_err("Couldn't get time scale");
+ return SR_ERR;
+ }
- //ToDo: Start capture
+ //set main timebase to show entire waveform. This is neccessary since the the windowed view can not be delayed outside the main view
+ //g_snprintf(command, sizeof(command), ":TIM:RANG %f", (1.0/((struct scope_state*)devc->model_state)->sample_rate)*points);
+ //sr_scpi_send(scpi, command);
+ sr_dbg("time ref is %s", tmp_string);
+ if(!strcmp(tmp_string, "LEFT")){
+ sr_dbg("left");
+ devc->timebaseLbound = tmp_float*-1;
+ } else if(!strcmp(tmp_string, "CENT")){
+ sr_dbg("cent");
+ devc->timebaseLbound = tmp_float*-5;
+ } else {
+ sr_dbg("right");
+ devc->timebaseLbound = tmp_float*-9;
+ }
+ devc->block_deltaT = 2000.0/((int)devc->sample_rate_limit);
+
+ devc->num_block_to_download = ceil(devc->samples_limit/2000); //ToDo: This needs some sanitization to make sure only available points are being downloaded
+ sr_dbg("Sample rate is: %d", state->sample_rate);
+ //Setup window view for first block download
+ g_snprintf(command, sizeof(command), ":TIM:MODE WIND;:TIM:WIND:RANG %f;:TIM:WIND:POS %f", devc->block_deltaT, devc->timebaseLbound+0.5*devc->block_deltaT);
+ sr_scpi_send(scpi, command);
+
+ sr_dbg("Download %d packets with a width of %f. Maxpoints are %d. Lbound is %f", devc->num_block_to_download, devc->block_deltaT, points, devc->timebaseLbound);
+
+ sr_dbg("beginning data download");
+ //make final setup before download
+ sr_scpi_send(scpi, ":WAV:FORM BYTE;BYT MSBF;UNS 0;POIN 2000"); //ToDo: when downloading high resolution data format needs to be word.
+
+ //get header data and store it in channel->priv so the receive_data function can submit it. This only needs to be done for analog channels
+ while(devc->current_channel){
+ ch = (struct sr_channel *)devc->current_channel->data;
+ if(ch->type == SR_CHANNEL_ANALOG){
+ ch->priv = (void *)g_malloc0(sizeof(struct analog_channel_transfer_info));
+ encoding = (struct analog_channel_transfer_info *)ch->priv;
+ sr_scpi_send(scpi, ":WAV:SOUR %s", ch->name);
+
+ //get signed
+ sr_scpi_get_bool(scpi, ":WAV:UNS?", &tmp_bool);
+ encoding->is_unsigned = tmp_bool;
+
+ //get transmission format. Byte is 1 byte per point, Word is 2 Byte per point
+ sr_scpi_get_string(scpi, ":WAV:FORM?", &tmp_string);
+ if(!strcmp("BYTE", tmp_string))
+ encoding->is_eightbit = TRUE;
+ else if(!strcmp("WORD", tmp_string))
+ encoding->is_eightbit = FALSE;
+ else{
+ sr_err("unknown transmission format");
+ }
+
+ sr_scpi_get_float(scpi, ":WAV:YINC?", &tmp_float);
+ encoding->yIncrement = tmp_float;
+
+ sr_scpi_get_float(scpi, ":WAV:YOR?", &tmp_float);
+ encoding->yOrigin = tmp_float;
+
+ sr_scpi_get_int(scpi, ":WAV:YREF?", &tmp_int);
+ sr_dbg("yRef is: %d", tmp_int);
+ encoding->yReference = tmp_int;
+
+ //ToDo: read data and write to encoding. dont forget to set and reset wav:source
+ sr_dbg("Reading data complete");
+ }
+ devc->current_channel = devc->current_channel->next;
+ };
+ devc->current_channel = devc->enabled_channels;
+ ch = (struct sr_channel *)devc->current_channel->data;
+ devc->failcount = 0;
+
+ //set waveform source channel to the first channel to be downloaded
+ ch = (struct sr_channel *)devc->enabled_channels->data;
+ if(ch->type == SR_CHANNEL_LOGIC){
+ group = ch->index/DIGITAL_CHANNELS_PER_POD+1;
+ g_snprintf(command, sizeof(command), ":WAV:SOUR POD%d", group);
+ } else {
+ g_snprintf(command, sizeof(command), ":WAV:SOUR %s", ch->name);
+ }
+ sr_scpi_send(scpi, command);
+
+ //register callback
+ sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 100, agilent_54621d_receive_data, (void *)sdi);
+
std_session_send_df_header(sdi);
+ std_session_send_df_frame_begin(sdi);
+
+ //request data from instrument
+ sr_scpi_send(scpi, ":WAV:DATA?");
+
+
return SR_OK;
@@ -664,11 +917,18 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
- /* TODO: stop acquisition. */
+ struct dev_context *devc;
+ struct sr_scpi_dev_inst *scpi;
- (void)sdi;
+ devc = sdi->priv;
- return SR_OK;
+ std_session_send_df_end(sdi);
+
+ g_slist_free(devc->enabled_channels);
+ devc->enabled_channels = NULL;
+ scpi = sdi->conn;
+ sr_scpi_source_remove(sdi->session, scpi);
+ sr_scpi_send(scpi, ":TIM:MODE MAIN");
}
static struct sr_dev_driver agilent_54621d_driver_info = {
diff --git a/src/hardware/agilent-54621d/protocol.c b/src/hardware/agilent-54621d/protocol.c
index 14c437c43..01af0c28e 100644
--- a/src/hardware/agilent-54621d/protocol.c
+++ b/src/hardware/agilent-54621d/protocol.c
@@ -24,6 +24,9 @@
#define MAX_COMMAND_SIZE 128
#define LOGIC_GET_THRESHOLD_SETTING "USER" //Threshold Setting that should be reported by the driver. Has to be included in logic_threshold. Has to be done in that hacky way since the device does only report threshold voltage level, yet not threshold setting
+#define WAIT_FOR_CAPTURE_COMPLETE_RETRIES 100
+#define WAIT_FOR_CAPTURE_COMPLETE_DELAY (100*1000)
+
static const char *agilent_scpi_dialect[] = {
[SCPI_CMD_GET_DIG_DATA] = ":FORM UINT,8;:POD%d:DATA?",
[SCPI_CMD_GET_TIMEBASE] = ":TIM:SCAL?", //OK
@@ -40,7 +43,7 @@ static const char *agilent_scpi_dialect[] = {
[SCPI_CMD_GET_TRIGGER_SOURCE] = ":TRIG:SOUR?", //Fixed
[SCPI_CMD_SET_TRIGGER_SOURCE] = ":TRIG:SOUR %s", //Fixed
[SCPI_CMD_GET_TRIGGER_SLOPE] = ":TRIG:SLOP?", //Fixed
- [SCPI_CMD_SET_TRIGGER_SLOPE] = ":TRIG:MODE EDGE;:TRIG:SLOP %s", //Fixed ?
+ [SCPI_CMD_SET_TRIGGER_SLOPE] = ":TRIG:MODE EDGE;:TRIG:SLOP %s", //Fixed
[SCPI_CMD_GET_TRIGGER_PATTERN] = ":TRIG:A:PATT:SOUR?",
[SCPI_CMD_SET_TRIGGER_PATTERN] = ":TRIG:A:TYPE LOGIC;" \
":TRIG:A:PATT:FUNC AND;" \
@@ -65,7 +68,7 @@ static const char *agilent_scpi_dialect[] = {
static const uint32_t devopts[] = {
SR_CONF_OSCILLOSCOPE,
- SR_CONF_SAMPLERATE | SR_CONF_GET,
+ SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_TIMEBASE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_NUM_HDIV | SR_CONF_GET,
SR_CONF_HORIZ_TRIGGERPOS | SR_CONF_GET | SR_CONF_SET,
@@ -76,6 +79,7 @@ static const uint32_t devopts[] = {
SR_CONF_PEAK_DETECTION | SR_CONF_GET | SR_CONF_SET,
// SR_CONF_AVERAGING | SR_CONF_GET | SR_CONF_SET,
SR_CONF_AVG_SAMPLES | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_DATA_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, //The device doesn't actually support limiting samples, but will allways capture the maximum available amout of samples. However the driver can selectively transfere a subset of samples inorder to reduce transfer times.
};
@@ -192,7 +196,7 @@ static const uint64_t vdivs[][2] = {
};
static const char *scope_analog_channel_names[] = {
- "CH1", "CH2",
+ "CHAN1", "CHAN2",
};
static const char *scope_digital_channel_names[] = {
@@ -248,28 +252,6 @@ static struct scope_config scope_models[] = {
//ToDo: Implement other scope models
};
-SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
-{
- const struct sr_dev_inst *sdi;
- struct dev_context *devc;
-
- (void)fd;
-
- sdi = cb_data;
- if (!sdi)
- return TRUE;
-
- devc = sdi->priv;
- if (!devc)
- return TRUE;
-
- if (revents == G_IO_IN) {
- /* TODO */
- }
-
- return TRUE;
-}
-
SR_PRIV int agilent_54621d_update_sample_rate(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
@@ -288,7 +270,8 @@ SR_PRIV int agilent_54621d_update_sample_rate(const struct sr_dev_inst *sdi)
state->sample_rate = tmp_int;
-
+ if(devc->sample_rate_limit > tmp_int)
+ devc->sample_rate_limit = tmp_int;
return SR_OK;
}
@@ -337,6 +320,7 @@ SR_PRIV int agilent_54621d_init_device(struct sr_dev_inst *sdi)
cg_name = (*scope_models[model_index].analog_names)[i];
devc->analog_groups[i] = sr_channel_group_new(sdi, cg_name, NULL);
devc->analog_groups[i]->channels = g_slist_append(NULL, ch);
+ //devc->analog_groups[i]->priv = (void *)g_malloc0(sizeof(struct analog_channel_transfer_info));
}
/* Add digital channel groups. */
@@ -365,6 +349,9 @@ SR_PRIV int agilent_54621d_init_device(struct sr_dev_inst *sdi)
devc->model_config = &scope_models[model_index];
devc->samples_limit = 2000;
devc->frame_limit = 0;
+ devc->data_source = DATA_SOURCE_LIVE;
+ devc->data = g_malloc(2000*sizeof(float));
+ devc->sample_rate_limit = SR_MHZ(200);
if (!(devc->model_state = scope_state_new(devc->model_config)))
return SR_ERR_MALLOC;
@@ -710,3 +697,270 @@ static int digital_channel_state_get(struct sr_dev_inst *sdi, const struct scope
return SR_OK;
}
+/* Queue data of one channel group, for later submission. */
+SR_PRIV void agilent_54621d_queue_logic_data(struct dev_context *devc,
+ size_t group, GByteArray *pod_data)
+{
+ size_t size;
+ GByteArray *store;
+ uint8_t *logic_data;
+ size_t idx, logic_step;
+
+ /*
+ * Upon first invocation, allocate the array which can hold the
+ * combined logic data for all channels. Assume that each channel
+ * will yield an identical number of samples per receive call.
+ *
+ * As a poor man's safety measure: (Silently) skip processing
+ * for unexpected sample counts, and ignore samples for
+ * unexpected channel groups. Don't bother with complicated
+ * resize logic, considering that many models only support one
+ * pod, and the most capable supported models have two pods of
+ * identical size. We haven't yet seen any "odd" configuration.
+ */
+ if (!devc->logic_data) {
+ size = pod_data->len * devc->pod_count; //ToDo: check if podcount is correctly set
+ store = g_byte_array_sized_new(size);
+ memset(store->data, 0, size);
+ store = g_byte_array_set_size(store, size);
+ devc->logic_data = store;
+ } else {
+ store = devc->logic_data;
+ size = store->len / devc->pod_count;
+ if (group >= devc->pod_count)
+ return;
+ }
+
+ /*
+ * Fold the data of the most recently received channel group into
+ * the storage, where data resides for all channels combined.
+ */
+ logic_data = store->data;
+ logic_data += group;
+ logic_step = devc->pod_count;
+ for (idx = 0; idx < pod_data->len; idx++) {
+ *logic_data = pod_data->data[idx];
+ logic_data += logic_step;
+ }
+
+ /* Truncate acquisition if a smaller number of samples has been requested. */
+ if (devc->samples_limit > 0 && devc->logic_data->len > devc->samples_limit * devc->pod_count)
+ devc->logic_data->len = devc->samples_limit * devc->pod_count;
+}
+
+/* Submit data for all channels, after the individual groups got collected. */
+SR_PRIV void agilent_54621d_send_logic_packet(struct sr_dev_inst *sdi,
+ struct dev_context *devc)
+{
+ struct sr_datafeed_packet packet;
+ struct sr_datafeed_logic logic;
+
+ if (!devc->logic_data)
+ return;
+
+ logic.data = devc->logic_data->data;
+ logic.length = devc->logic_data->len;
+ logic.unitsize = devc->pod_count;
+
+ packet.type = SR_DF_LOGIC;
+ packet.payload = &logic;
+
+ sr_session_send(sdi, &packet);
+}
+
+/* Undo previous resource allocation. */
+SR_PRIV void agilent_54621d_cleanup_logic_data(struct dev_context *devc)
+{
+
+ if (devc->logic_data) {
+ g_byte_array_free(devc->logic_data, TRUE);
+ devc->logic_data = NULL;
+ }
+ /*
+ * Keep 'pod_count'! It's required when more frames will be
+ * received, and does not harm when kept after acquisition.
+ */
+}
+
+
+SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
+{
+ struct sr_channel *ch;
+ struct sr_dev_inst *sdi;
+ struct dev_context *devc;
+ struct scope_state *state;
+ struct sr_datafeed_packet packet;
+ GByteArray *data;
+ struct sr_datafeed_analog analog;
+ struct sr_analog_encoding encoding;
+ struct sr_analog_meaning meaning;
+ struct sr_analog_spec spec;
+ struct sr_datafeed_logic logic;
+ size_t group;
+ int i;
+ struct analog_channel_transfer_info *info;
+ signed int tmp_int;
+ char command[MAX_COMMAND_SIZE];
+
+ float timebase_offset;
+
+ float tmp_float;
+
+ (void)fd;
+ (void)revents;
+
+ if (!(sdi = cb_data))
+ return TRUE;
+
+ if (!(devc = sdi->priv))
+ return TRUE;
+
+ ch = devc->current_channel->data;
+ state = devc->model_state;
+
+
+
+ switch (ch->type){
+ case SR_CHANNEL_ANALOG:
+ info = (struct analog_channel_transfer_info *)ch->priv;
+ data = NULL;
+ if(sr_scpi_get_block(sdi->conn, NULL, &data) != SR_OK){
+ if(data)
+ g_byte_array_free(data, TRUE);
+ sr_err("Failed to retreive block");
+ devc->failcount++;
+ if(devc->failcount>=3){
+ sr_scpi_send(sdi->conn, ":WAV:DATA?");
+ devc->failcount=0;
+ }
+
+ return TRUE;
+ }
+ devc->failcount=0;
+
+ //Append downloaded block to buffer -- This should no longer be neccessary
+ //g_byte_array_append(devc->buffer, data->data, data->len);
+
+
+ sr_dbg("yRef: %d, yInc: %f, yOri: %f", info->yReference, info->yIncrement, info->yOrigin);
+ for(i = 0; ilen; i++){
+ tmp_int=(int8_t)data->data[i];
+ devc->data[i] = (((float)(tmp_int) - info->yReference) * info->yIncrement) + info->yOrigin;
+ }
+ sr_analog_init(&analog, &encoding, &meaning, &spec, 2); //ToDo: 2 digits is just placeholder. needs to be calculated correctly
+ analog.meaning->channels = g_slist_append(NULL, ch);
+ analog.num_samples = data->len;
+ analog.data = devc->data;
+ analog.meaning->mq = SR_MQ_VOLTAGE;
+ analog.meaning->unit = SR_UNIT_VOLT;
+ analog.meaning->mqflags = 0;
+
+ packet.type = SR_DF_ANALOG;
+ packet.payload = &analog;
+ sr_session_send(sdi, &packet);
+
+ g_slist_free(analog.meaning->channels);
+
+
+ g_byte_array_free(data, TRUE);
+ data = NULL;
+ break;
+ case SR_CHANNEL_LOGIC:
+ data = NULL;
+ if(sr_scpi_get_block(sdi->conn, NULL, &data) != SR_OK){
+ if(data)
+ g_byte_array_free(data, TRUE);
+ sr_err("Failed to retreive block");
+ devc->failcount++;
+ if(devc->failcount>=3){
+ sr_scpi_send(sdi->conn, ":WAV:DATA?");
+ devc->failcount=0;
+ }
+
+ return TRUE;
+ }
+ devc->failcount=0;
+
+ group = ch->index / DIGITAL_CHANNELS_PER_POD;
+ agilent_54621d_queue_logic_data(devc, group, data);
+
+
+ break;
+ default:
+ sr_err("Invalid channel type");
+ break;
+ }
+
+ //if more channels need to be downloaded for the current frame
+ if(devc->current_channel->next){
+ devc->current_channel = devc->current_channel->next;
+ //sr_scpi_send(sdi->conn, ":WAV:SOUR %s;DATA?", ((struct sr_channel *)devc->current_channel->data)->name);
+ ch = (struct sr_channel *)devc->current_channel->data;
+ if(ch->type == SR_CHANNEL_LOGIC){
+ group = ch->index/DIGITAL_CHANNELS_PER_POD+1;
+ g_snprintf(command, sizeof(command), ":WAV:SOUR POD%d;DATA?", group);
+ } else {
+ g_snprintf(command, sizeof(command), ":WAV:SOUR %s;UNS 0;DATA?", ch->name);
+ }
+ sr_scpi_send(sdi->conn, command);
+ return TRUE;
+ }
+ agilent_54621d_send_logic_packet(sdi, devc);
+
+ //if more blocks need to be downloaded
+ sr_dbg("Downloaded %d/%d datablocks", devc->num_blocks_downloaded, devc->num_block_to_download);
+ if(devc->num_blocks_downloaded < devc->num_block_to_download){
+ devc->num_blocks_downloaded++;
+ devc->current_channel = devc->enabled_channels;
+ timebase_offset = devc->timebaseLbound+(devc->num_blocks_downloaded+0.5)*devc->block_deltaT;
+ sr_scpi_send(sdi->conn, ":TIM:WIND:POS %f", timebase_offset);
+ //sr_scpi_send(sdi->conn, ":WAV:SOUR %s;DATA?", ((struct sr_channel *)devc->current_channel->data)->name);
+ ch = (struct sr_channel *)devc->current_channel->data;
+ if(ch->type == SR_CHANNEL_LOGIC){
+ group = ch->index/DIGITAL_CHANNELS_PER_POD+1;
+ g_snprintf(command, sizeof(command), ":WAV:SOUR POD%d;DATA?", group);
+ } else {
+ g_snprintf(command, sizeof(command), ":WAV:SOUR %s;UNS 0;DATA?", ch->name);
+ }
+ sr_scpi_send(sdi->conn, command);
+
+ return TRUE;
+ } else {
+ agilent_54621d_cleanup_logic_data(devc);
+ std_session_send_df_frame_end(sdi);
+ sr_dev_acquisition_stop(sdi);
+ return TRUE;
+ }
+}
+
+SR_PRIV int agilent_54621d_request_data(const struct sr_dev_inst *sdi)
+{
+
+}
+
+
+
+/*static int wait_for_capture_complete(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ struct sr_scpi_dev_inst *scpi = sdi->conn;
+ int tmp_int;
+ int i;
+ gboolean acquisition_complete;
+
+ if(!(devc = sdi->priv))
+ return SR_ERR;
+
+ for(i = 0; i device is stopped. This should be the case once the acquisition is complete
+ return SR_OK;
+ }
+ g_usleep(WAIT_FOR_CAPTURE_COMPLETE_DELAY);
+ }
+
+ sr_err("Capture Timed out");
+ return SR_ERR;
+
+}*/
+
diff --git a/src/hardware/agilent-54621d/protocol.h b/src/hardware/agilent-54621d/protocol.h
index abf64b8a8..31cb528cc 100644
--- a/src/hardware/agilent-54621d/protocol.h
+++ b/src/hardware/agilent-54621d/protocol.h
@@ -38,6 +38,11 @@
#define MAX_DIGITAL_GROUP_COUNT 2
+enum data_source {
+ DATA_SOURCE_LIVE,
+ DATA_SOURCE_MEMORY,
+};
+
struct scope_config {
const char *name[MAX_INSTRUMENT_VERSIONS];
const uint8_t analog_channels;
@@ -91,6 +96,14 @@ struct analog_channel_state {
char probe_unit;
};
+struct analog_channel_transfer_info {
+ int yReference;
+ float yOrigin;
+ float yIncrement;
+ gboolean is_unsigned;
+ gboolean is_eightbit;
+};
+
struct digital_pod_state {
gboolean state;
@@ -127,6 +140,8 @@ struct dev_context {
struct sr_channel_group **analog_groups;
struct sr_channel_group **digital_groups;
+ enum data_source data_source;
+
GSList *enabled_channels;
GSList *current_channel;
uint64_t num_samples;
@@ -136,18 +151,33 @@ struct dev_context {
uint64_t frame_limit;
size_t pod_count;
- GByteArray *logic_data;
+
+ //helper variables for data download
+ uint64_t sample_rate_limit;
+ GByteArray *buffer;
+ GSList *channels_to_download;
+ int num_block_to_download;
+ int num_blocks_downloaded;
+ float block_deltaT;
+ float timebaseLbound;
+ gboolean headerSent;
+ float *data;
+ int failcount;
+ GByteArray *logic_data;
};
SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int agilent_54621d_request_data(const struct sr_dev_inst *sdi);
SR_PRIV int agilent_54621d_init_device(struct sr_dev_inst *sdi);
SR_PRIV int agilent_54621d_scope_state_get(struct sr_dev_inst *sdi);
SR_PRIV int agilent_54621d_update_sample_rate(const struct sr_dev_inst *sdi);
static struct scope_state *scope_state_new(const struct scope_config *config);
+
static int analog_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
static int digital_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
static int array_float_get(gchar *value, const uint64_t array[][2], int array_len, unsigned int *result);
static void scope_state_dump(const struct scope_config *config, struct scope_state *state);
static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi, const char *command, const char *(*array)[], unsigned int n, int *result);
+//static int wait_for_capture_complete(const struct sr_dev_inst *sdi);
#endif
From 0ab616626b5f86a6436e5951725ac7fae6e1cf9d Mon Sep 17 00:00:00 2001
From: Daniel <1824222@stud.hs-mannheim.de>
Date: Sun, 15 Jan 2023 16:31:03 +0100
Subject: [PATCH 3/9] fixed digital download and increased stability
---
src/hardware/agilent-54621d/api.c | 12 +++++++++++-
src/hardware/agilent-54621d/protocol.c | 11 +++++++++--
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/src/hardware/agilent-54621d/api.c b/src/hardware/agilent-54621d/api.c
index 9bc56bfbc..23a5ee04b 100644
--- a/src/hardware/agilent-54621d/api.c
+++ b/src/hardware/agilent-54621d/api.c
@@ -840,7 +840,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
devc->num_block_to_download = ceil(devc->samples_limit/2000); //ToDo: This needs some sanitization to make sure only available points are being downloaded
sr_dbg("Sample rate is: %d", state->sample_rate);
//Setup window view for first block download
- g_snprintf(command, sizeof(command), ":TIM:MODE WIND;:TIM:WIND:RANG %f;:TIM:WIND:POS %f", devc->block_deltaT, devc->timebaseLbound+0.5*devc->block_deltaT);
+ g_snprintf(command, sizeof(command), ":TIM:MODE MAIN;:TIM:RANG %f;:TIM:DEL %f", devc->block_deltaT, devc->timebaseLbound+0.5*devc->block_deltaT);
sr_scpi_send(scpi, command);
sr_dbg("Download %d packets with a width of %f. Maxpoints are %d. Lbound is %f", devc->num_block_to_download, devc->block_deltaT, points, devc->timebaseLbound);
@@ -907,6 +907,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
std_session_send_df_frame_begin(sdi);
//request data from instrument
+ sr_scpi_send(scpi, ":SYST:DSP \"Reading Block 1/%d\"", devc->num_block_to_download);
sr_scpi_send(scpi, ":WAV:DATA?");
@@ -919,15 +920,24 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct sr_scpi_dev_inst *scpi;
+ const struct scope_config *model;
+ struct scope_state *state;
+ float timebase;
devc = sdi->priv;
+ model = devc->model_config;
+ state = devc->model_state;
std_session_send_df_end(sdi);
+ timebase = (float) (*model->timebases)[state->timebase][0] / (*model->timebases)[state->timebase][1];
+
g_slist_free(devc->enabled_channels);
devc->enabled_channels = NULL;
scpi = sdi->conn;
sr_scpi_source_remove(sdi->session, scpi);
+ sr_scpi_send(scpi, ":SYST:DSP \"\"");
+ sr_scpi_send(scpi, ":TIM:RANG %f; :TIM:DEL 0", timebase);
sr_scpi_send(scpi, ":TIM:MODE MAIN");
}
diff --git a/src/hardware/agilent-54621d/protocol.c b/src/hardware/agilent-54621d/protocol.c
index 01af0c28e..62f437c40 100644
--- a/src/hardware/agilent-54621d/protocol.c
+++ b/src/hardware/agilent-54621d/protocol.c
@@ -806,6 +806,8 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
float tmp_float;
+ char *tmp_string;
+
(void)fd;
(void)revents;
@@ -891,6 +893,10 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
break;
}
+ //Sometimes the trailing \nl on a datablock is received delayed an not read by the sr_get_data_block. therefore we try to read a response and just dismiss it if there is any
+ if(sr_scpi_read_data(sdi->conn, &tmp_string, 1) == SR_OK)
+ sr_info("Received delayed NL on block download");
+
//if more channels need to be downloaded for the current frame
if(devc->current_channel->next){
devc->current_channel = devc->current_channel->next;
@@ -909,11 +915,12 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
//if more blocks need to be downloaded
sr_dbg("Downloaded %d/%d datablocks", devc->num_blocks_downloaded, devc->num_block_to_download);
- if(devc->num_blocks_downloaded < devc->num_block_to_download){
+ if(devc->num_blocks_downloaded+1 < devc->num_block_to_download){
devc->num_blocks_downloaded++;
devc->current_channel = devc->enabled_channels;
timebase_offset = devc->timebaseLbound+(devc->num_blocks_downloaded+0.5)*devc->block_deltaT;
- sr_scpi_send(sdi->conn, ":TIM:WIND:POS %f", timebase_offset);
+ sr_scpi_send(sdi->conn, ":TIM:DEL %f", timebase_offset);
+ sr_scpi_send(sdi->conn, ":SYST:DSP \"Reading Block %d/%d\"", devc->num_blocks_downloaded+1, devc->num_block_to_download);
//sr_scpi_send(sdi->conn, ":WAV:SOUR %s;DATA?", ((struct sr_channel *)devc->current_channel->data)->name);
ch = (struct sr_channel *)devc->current_channel->data;
if(ch->type == SR_CHANNEL_LOGIC){
From edbf7a1015b8fda488cba99f6393035a5b637ab3 Mon Sep 17 00:00:00 2001
From: Daniel <1824222@stud.hs-mannheim.de>
Date: Sun, 15 Jan 2023 19:55:34 +0100
Subject: [PATCH 4/9] v0.1
---
src/hardware/agilent-54621d/api.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/src/hardware/agilent-54621d/api.c b/src/hardware/agilent-54621d/api.c
index 23a5ee04b..857bd9d2d 100644
--- a/src/hardware/agilent-54621d/api.c
+++ b/src/hardware/agilent-54621d/api.c
@@ -667,6 +667,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
gboolean channel_available;
gboolean digital_added[MAX_DIGITAL_GROUP_COUNT];
size_t group, pod_count;
+ struct sr_datafeed_packet packet;
+ struct sr_datafeed_header header;
+ struct timeval timeToTrigger;
+
scpi = sdi->conn;
devc = sdi->priv;
@@ -720,7 +724,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
//ToDo: this is a hacky workaround to get what channel groups need to be downloaded. Ther surely is a better way to do this.
//ToDo2: Is this even used?
- devc->channels_to_download = NULL;
+ /*devc->channels_to_download = NULL;
for(i = 0; ichannels_to_download = g_slist_append(devc->channels_to_download, data_channels[i]);
- }
+ }*/
//Sample rate needs to be updated if channels have been changed, since in some channel configurations sample rate is reduced
if(TRUE){
@@ -761,7 +765,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
return SR_ERR;
}
} else if (devc->data_source == DATA_SOURCE_MEMORY) {
- g_snprintf(command, sizeof(command), ":WAV:SOUR %s", devc->channels_to_download[0]);
+ ch = (struct sr_channel *)devc->current_channel->data;
+ g_snprintf(command, sizeof(command), ":WAV:SOUR %s", ch->name);
sr_scpi_send(scpi, command);
sr_scpi_get_int(scpi, ":WAV:POIN? MAX", &tmp_int);
if(tmp_int <= 0){
@@ -903,7 +908,17 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
//register callback
sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 100, agilent_54621d_receive_data, (void *)sdi);
- std_session_send_df_header(sdi);
+
+ packet.type = SR_DF_HEADER;
+ packet.payload = (uint8_t *)&header;
+ header.feed_version = 1;
+ header.starttime.tv_sec = 0;
+ header.starttime.tv_usec = 1000000.0*devc->timebaseLbound;
+ sr_dbg("Pretrigger time: %d", header.starttime.tv_usec);
+ sr_session_send(sdi, &packet);
+
+
+ //std_session_send_df_header(sdi);
std_session_send_df_frame_begin(sdi);
//request data from instrument
@@ -937,7 +952,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
scpi = sdi->conn;
sr_scpi_source_remove(sdi->session, scpi);
sr_scpi_send(scpi, ":SYST:DSP \"\"");
- sr_scpi_send(scpi, ":TIM:RANG %f; :TIM:DEL 0", timebase);
+ sr_scpi_send(scpi, ":TIM:SCAL %f; :TIM:DEL 0", timebase);
sr_scpi_send(scpi, ":TIM:MODE MAIN");
}
From ff5678743d193b08b41018cbe740ed3cace1a319 Mon Sep 17 00:00:00 2001
From: Daniel <1824222@stud.hs-mannheim.de>
Date: Mon, 16 Jan 2023 20:39:36 +0100
Subject: [PATCH 5/9] fixed various issues and improved stability
---
src/hardware/agilent-54621d/api.c | 41 +++++++--------
src/hardware/agilent-54621d/protocol.c | 71 +++++++++-----------------
src/hardware/agilent-54621d/protocol.h | 6 ---
3 files changed, 42 insertions(+), 76 deletions(-)
diff --git a/src/hardware/agilent-54621d/api.c b/src/hardware/agilent-54621d/api.c
index 857bd9d2d..55922026f 100644
--- a/src/hardware/agilent-54621d/api.c
+++ b/src/hardware/agilent-54621d/api.c
@@ -54,13 +54,6 @@ static const char *data_sources[] = {
"Memory",
};
-static const char *data_channels[] = {
- "CHAN1",
- "CHAN2",
- "POD1",
- "POD2",
-};
-
static const uint64_t samplerates[] = {
SR_HZ(1),
SR_MHZ(200),
@@ -97,6 +90,10 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
struct dev_context *devc;
struct sr_scpi_hw_info *hw_info;
+ sdi = NULL;
+ devc = NULL;
+ hw_info = NULL;
+
if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
sr_info("Couldn't get IDN response.");
goto fail;
@@ -187,7 +184,7 @@ static int check_channel_group(struct dev_context *devc,
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
- int cg_type, idx, i;
+ int cg_type, idx;
struct dev_context *devc;
const struct scope_config *model;
struct scope_state *state;
@@ -314,18 +311,22 @@ static int config_get(uint32_t key, GVariant **data,
return SR_OK;
}
+
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
int ret, cg_type, idx, i, j;
- char command[MAX_COMMAND_SIZE], command2[MAX_COMMAND_SIZE];
- char float_str[30], *tmp_str;
+ char command[MAX_COMMAND_SIZE];
+ char float_str[30];
struct dev_context *devc;
const struct scope_config *model;
struct scope_state *state;
double tmp_d, tmp_d2;
gboolean update_sample_rate, tmp_bool;
int tmp_int;
+ const char *tmp_str;
+
+ ret = SR_ERR;
if (!sdi)
return SR_ERR_ARG;
@@ -651,10 +652,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct sr_scpi_dev_inst *scpi;
struct scope_state *state;
const struct scope_config *model;
- int ret, i;
- char *cmd;
- gboolean state_changed;
- volatile int tmp_int;
+ int i;
+ int tmp_int;
gboolean acq_complete;
gboolean tmp_bool;
char command[MAX_COMMAND_SIZE];
@@ -663,8 +662,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
char *tmp_string;
float tmp_float;
struct analog_channel_transfer_info *encoding;
- int xref;
- gboolean channel_available;
gboolean digital_added[MAX_DIGITAL_GROUP_COUNT];
size_t group, pod_count;
struct sr_datafeed_packet packet;
@@ -685,7 +682,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
digital_added[group] = FALSE;
g_slist_free(devc->enabled_channels);
devc->enabled_channels = NULL;
- state_changed = FALSE;
pod_count = 0;
for (l = sdi->channels; l; l = l->next) {
@@ -700,7 +696,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
sr_scpi_get_opc(scpi) != SR_OK)
return SR_ERR;
state->analog_channels[ch->index].state = ch->enabled;
- state_changed = TRUE;
}
} else if (ch->type == SR_CHANNEL_LOGIC) {
group = ch->index / DIGITAL_CHANNELS_PER_POD;
@@ -715,7 +710,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
sr_scpi_get_opc(scpi) != SR_OK)
return SR_ERR;
state->digital_channels[ch->index] = ch->enabled;
- state_changed = TRUE;
}
}
}
@@ -798,7 +792,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
ch = (struct sr_channel *)devc->enabled_channels->data;
if(ch->type == SR_CHANNEL_LOGIC){
group = ch->index/DIGITAL_CHANNELS_PER_POD+1;
- g_snprintf(command, sizeof(command), ":WAV:SOUR POD%d", group);
+ g_snprintf(command, sizeof(command), ":WAV:SOUR POD%ld", group);
} else {
g_snprintf(command, sizeof(command), ":WAV:SOUR %s", ch->name);
}
@@ -843,7 +837,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
devc->block_deltaT = 2000.0/((int)devc->sample_rate_limit);
devc->num_block_to_download = ceil(devc->samples_limit/2000); //ToDo: This needs some sanitization to make sure only available points are being downloaded
- sr_dbg("Sample rate is: %d", state->sample_rate);
+ sr_dbg("Sample rate is: %ld", state->sample_rate);
//Setup window view for first block download
g_snprintf(command, sizeof(command), ":TIM:MODE MAIN;:TIM:RANG %f;:TIM:DEL %f", devc->block_deltaT, devc->timebaseLbound+0.5*devc->block_deltaT);
sr_scpi_send(scpi, command);
@@ -899,7 +893,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
ch = (struct sr_channel *)devc->enabled_channels->data;
if(ch->type == SR_CHANNEL_LOGIC){
group = ch->index/DIGITAL_CHANNELS_PER_POD+1;
- g_snprintf(command, sizeof(command), ":WAV:SOUR POD%d", group);
+ g_snprintf(command, sizeof(command), ":WAV:SOUR POD%ld", group);
} else {
g_snprintf(command, sizeof(command), ":WAV:SOUR %s", ch->name);
}
@@ -914,7 +908,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
header.feed_version = 1;
header.starttime.tv_sec = 0;
header.starttime.tv_usec = 1000000.0*devc->timebaseLbound;
- sr_dbg("Pretrigger time: %d", header.starttime.tv_usec);
+ sr_dbg("Pretrigger time: %ld.", header.starttime.tv_usec);
sr_session_send(sdi, &packet);
@@ -954,6 +948,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
sr_scpi_send(scpi, ":SYST:DSP \"\"");
sr_scpi_send(scpi, ":TIM:SCAL %f; :TIM:DEL 0", timebase);
sr_scpi_send(scpi, ":TIM:MODE MAIN");
+ return SR_OK;
}
static struct sr_dev_driver agilent_54621d_driver_info = {
diff --git a/src/hardware/agilent-54621d/protocol.c b/src/hardware/agilent-54621d/protocol.c
index 62f437c40..1a283f155 100644
--- a/src/hardware/agilent-54621d/protocol.c
+++ b/src/hardware/agilent-54621d/protocol.c
@@ -21,6 +21,20 @@
#include "protocol.h"
#include "scpi.h"
+SR_PRIV void agilent_54621d_queue_logic_data(struct dev_context *devc,
+ size_t group, GByteArray *pod_data);
+SR_PRIV void agilent_54621d_send_logic_packet(struct sr_dev_inst *sdi,
+ struct dev_context *devc);
+SR_PRIV void agilent_54621d_cleanup_logic_data(struct dev_context *devc);
+
+static struct scope_state *scope_state_new(const struct scope_config *config);
+
+static int analog_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
+static int digital_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
+static int array_float_get(gchar *value, const uint64_t array[][2], int array_len, unsigned int *result);
+static void scope_state_dump(const struct scope_config *config, struct scope_state *state);
+static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi, const char *command, const char *(*array)[], unsigned int n, int *result);
+
#define MAX_COMMAND_SIZE 128
#define LOGIC_GET_THRESHOLD_SETTING "USER" //Threshold Setting that should be reported by the driver. Has to be included in logic_threshold. Has to be done in that hacky way since the device does only report threshold voltage level, yet not threshold setting
@@ -257,7 +271,7 @@ SR_PRIV int agilent_54621d_update_sample_rate(const struct sr_dev_inst *sdi)
struct dev_context *devc;
struct scope_state *state;
const struct scope_config *config;
- uint64_t tmp_int;
+ int tmp_int;
devc = sdi->priv;
config = devc->model_config;
@@ -270,7 +284,7 @@ SR_PRIV int agilent_54621d_update_sample_rate(const struct sr_dev_inst *sdi)
state->sample_rate = tmp_int;
- if(devc->sample_rate_limit > tmp_int)
+ if(devc->sample_rate_limit > (uint64_t)tmp_int)
devc->sample_rate_limit = tmp_int;
return SR_OK;
@@ -428,7 +442,7 @@ SR_PRIV int agilent_54621d_scope_state_get(struct sr_dev_inst *sdi)
//ToDo: get trigger pattern
//documentation for reading the trigger pattern is a little wonky so I need to test how this is done
- strncpy(state->trigger_pattern, "0000000000000000000000", MAX_ANALOG_CHANNEL_COUNT + MAX_DIGITAL_CHANNEL_COUNT);
+ strncpy(state->trigger_pattern, "00000000000000000000", MAX_ANALOG_CHANNEL_COUNT + MAX_DIGITAL_CHANNEL_COUNT+1);
//ToDo: get current resolution
@@ -788,26 +802,22 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
struct sr_channel *ch;
struct sr_dev_inst *sdi;
struct dev_context *devc;
- struct scope_state *state;
struct sr_datafeed_packet packet;
GByteArray *data;
struct sr_datafeed_analog analog;
struct sr_analog_encoding encoding;
struct sr_analog_meaning meaning;
struct sr_analog_spec spec;
- struct sr_datafeed_logic logic;
size_t group;
int i;
struct analog_channel_transfer_info *info;
signed int tmp_int;
char command[MAX_COMMAND_SIZE];
-
float timebase_offset;
-
- float tmp_float;
-
char *tmp_string;
+ tmp_string = NULL;
+
(void)fd;
(void)revents;
@@ -818,9 +828,6 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
return TRUE;
ch = devc->current_channel->data;
- state = devc->model_state;
-
-
switch (ch->type){
case SR_CHANNEL_ANALOG:
@@ -845,7 +852,7 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
sr_dbg("yRef: %d, yInc: %f, yOri: %f", info->yReference, info->yIncrement, info->yOrigin);
- for(i = 0; ilen; i++){
+ for(i = 0; i<(int)data->len; i++){
tmp_int=(int8_t)data->data[i];
devc->data[i] = (((float)(tmp_int) - info->yReference) * info->yIncrement) + info->yOrigin;
}
@@ -894,7 +901,7 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
}
//Sometimes the trailing \nl on a datablock is received delayed an not read by the sr_get_data_block. therefore we try to read a response and just dismiss it if there is any
- if(sr_scpi_read_data(sdi->conn, &tmp_string, 1) == SR_OK)
+ if(sr_scpi_read_data(sdi->conn, tmp_string, 1) == SR_OK)
sr_info("Received delayed NL on block download");
//if more channels need to be downloaded for the current frame
@@ -904,7 +911,7 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
ch = (struct sr_channel *)devc->current_channel->data;
if(ch->type == SR_CHANNEL_LOGIC){
group = ch->index/DIGITAL_CHANNELS_PER_POD+1;
- g_snprintf(command, sizeof(command), ":WAV:SOUR POD%d;DATA?", group);
+ g_snprintf(command, sizeof(command), ":WAV:SOUR POD%ld;DATA?", group);
} else {
g_snprintf(command, sizeof(command), ":WAV:SOUR %s;UNS 0;DATA?", ch->name);
}
@@ -925,7 +932,7 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
ch = (struct sr_channel *)devc->current_channel->data;
if(ch->type == SR_CHANNEL_LOGIC){
group = ch->index/DIGITAL_CHANNELS_PER_POD+1;
- g_snprintf(command, sizeof(command), ":WAV:SOUR POD%d;DATA?", group);
+ g_snprintf(command, sizeof(command), ":WAV:SOUR POD%ld;DATA?", group);
} else {
g_snprintf(command, sizeof(command), ":WAV:SOUR %s;UNS 0;DATA?", ch->name);
}
@@ -938,36 +945,6 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
sr_dev_acquisition_stop(sdi);
return TRUE;
}
+ return FALSE;
}
-SR_PRIV int agilent_54621d_request_data(const struct sr_dev_inst *sdi)
-{
-
-}
-
-
-
-/*static int wait_for_capture_complete(const struct sr_dev_inst *sdi)
-{
- struct dev_context *devc;
- struct sr_scpi_dev_inst *scpi = sdi->conn;
- int tmp_int;
- int i;
- gboolean acquisition_complete;
-
- if(!(devc = sdi->priv))
- return SR_ERR;
-
- for(i = 0; i device is stopped. This should be the case once the acquisition is complete
- return SR_OK;
- }
- g_usleep(WAIT_FOR_CAPTURE_COMPLETE_DELAY);
- }
-
- sr_err("Capture Timed out");
- return SR_ERR;
-
-}*/
-
diff --git a/src/hardware/agilent-54621d/protocol.h b/src/hardware/agilent-54621d/protocol.h
index 31cb528cc..5c1fbcdef 100644
--- a/src/hardware/agilent-54621d/protocol.h
+++ b/src/hardware/agilent-54621d/protocol.h
@@ -171,13 +171,7 @@ SR_PRIV int agilent_54621d_request_data(const struct sr_dev_inst *sdi);
SR_PRIV int agilent_54621d_init_device(struct sr_dev_inst *sdi);
SR_PRIV int agilent_54621d_scope_state_get(struct sr_dev_inst *sdi);
SR_PRIV int agilent_54621d_update_sample_rate(const struct sr_dev_inst *sdi);
-static struct scope_state *scope_state_new(const struct scope_config *config);
-static int analog_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
-static int digital_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
-static int array_float_get(gchar *value, const uint64_t array[][2], int array_len, unsigned int *result);
-static void scope_state_dump(const struct scope_config *config, struct scope_state *state);
-static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi, const char *command, const char *(*array)[], unsigned int n, int *result);
//static int wait_for_capture_complete(const struct sr_dev_inst *sdi);
#endif
From 28e4ac682ffa5c69cddf060537f2c9732afd3c88 Mon Sep 17 00:00:00 2001
From: Daniel <1824222@stud.hs-mannheim.de>
Date: Fri, 20 Jan 2023 23:29:48 +0100
Subject: [PATCH 6/9] fixed trigger position
---
src/hardware/agilent-54621d/api.c | 43 +++------
src/hardware/agilent-54621d/protocol.c | 124 +++++++++++++++++++------
src/hardware/agilent-54621d/protocol.h | 3 +
3 files changed, 112 insertions(+), 58 deletions(-)
diff --git a/src/hardware/agilent-54621d/api.c b/src/hardware/agilent-54621d/api.c
index 55922026f..2e806b1ec 100644
--- a/src/hardware/agilent-54621d/api.c
+++ b/src/hardware/agilent-54621d/api.c
@@ -50,7 +50,7 @@ enum {
//Do not change order
static const char *data_sources[] = {
- "Live",
+ "Single",
"Memory",
};
@@ -298,7 +298,7 @@ static int config_get(uint32_t key, GVariant **data,
break;
case SR_CONF_DATA_SOURCE:
if (devc->data_source == DATA_SOURCE_LIVE)
- *data = g_variant_new_string("Live");
+ *data = g_variant_new_string("Single");
else if (devc->data_source == DATA_SOURCE_MEMORY)
*data = g_variant_new_string("Memory");
break;
@@ -535,7 +535,7 @@ static int config_set(uint32_t key, GVariant *data,
case SR_CONF_DATA_SOURCE:
tmp_str = g_variant_get_string(data, NULL);
sr_dbg("Setting data source to: '%s'", tmp_str);
- if(!strcmp(tmp_str, "Live"))
+ if(!strcmp(tmp_str, "Single"))
devc->data_source = DATA_SOURCE_LIVE;
else if(!strcmp(tmp_str, "Memory"))
devc->data_source = DATA_SOURCE_MEMORY;
@@ -716,29 +716,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
devc->current_channel = devc->enabled_channels;
devc->pod_count = pod_count;
- //ToDo: this is a hacky workaround to get what channel groups need to be downloaded. Ther surely is a better way to do this.
- //ToDo2: Is this even used?
- /*devc->channels_to_download = NULL;
- for(i = 0; ichannels_to_download = g_slist_append(devc->channels_to_download, data_channels[i]);
- }*/
-
- //Sample rate needs to be updated if channels have been changed, since in some channel configurations sample rate is reduced
- if(TRUE){
- sr_scpi_send(scpi, ":RUN"); //Device needs to run in order to get the correct sample rate
- if(sr_scpi_get_opc(scpi) != SR_OK){
- sr_err("Couldnt set device to running");
- return SR_ERR;
- }
- if(agilent_54621d_update_sample_rate(sdi) != SR_OK)
- return SR_ERR;
- }
if(devc->data_source == DATA_SOURCE_LIVE){
sr_scpi_send(scpi, ":SING");
@@ -826,23 +803,25 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
sr_dbg("time ref is %s", tmp_string);
if(!strcmp(tmp_string, "LEFT")){
sr_dbg("left");
- devc->timebaseLbound = tmp_float*-1;
+ devc->refPos = -1;
} else if(!strcmp(tmp_string, "CENT")){
sr_dbg("cent");
- devc->timebaseLbound = tmp_float*-5;
+ devc->refPos = -5;
} else {
sr_dbg("right");
- devc->timebaseLbound = tmp_float*-9;
+ devc->refPos = -9;
}
+ devc->timebaseLbound = tmp_float*devc->refPos;
devc->block_deltaT = 2000.0/((int)devc->sample_rate_limit);
devc->num_block_to_download = ceil(devc->samples_limit/2000); //ToDo: This needs some sanitization to make sure only available points are being downloaded
+ devc->trigger_at_sample = (uint64_t)((-devc->timebaseLbound)*(devc->sample_rate_limit));
sr_dbg("Sample rate is: %ld", state->sample_rate);
//Setup window view for first block download
- g_snprintf(command, sizeof(command), ":TIM:MODE MAIN;:TIM:RANG %f;:TIM:DEL %f", devc->block_deltaT, devc->timebaseLbound+0.5*devc->block_deltaT);
+ g_snprintf(command, sizeof(command), ":TIM:MODE MAIN;:TIM:RANG %f;:TIM:DEL %f", devc->block_deltaT, devc->timebaseLbound-devc->refPos*devc->block_deltaT*0.1);
sr_scpi_send(scpi, command);
- sr_dbg("Download %d packets with a width of %f. Maxpoints are %d. Lbound is %f", devc->num_block_to_download, devc->block_deltaT, points, devc->timebaseLbound);
+ sr_dbg("Download %d packets with a width of %f. Maxpoints are %d. Lbound is %f. Trigger at sample %d", devc->num_block_to_download, devc->block_deltaT, points, devc->timebaseLbound, devc->trigger_at_sample);
sr_dbg("beginning data download");
//make final setup before download
@@ -888,6 +867,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
devc->current_channel = devc->enabled_channels;
ch = (struct sr_channel *)devc->current_channel->data;
devc->failcount = 0;
+ devc->trigger_sent = FALSE;
+
//set waveform source channel to the first channel to be downloaded
ch = (struct sr_channel *)devc->enabled_channels->data;
diff --git a/src/hardware/agilent-54621d/protocol.c b/src/hardware/agilent-54621d/protocol.c
index 1a283f155..e66e6ad45 100644
--- a/src/hardware/agilent-54621d/protocol.c
+++ b/src/hardware/agilent-54621d/protocol.c
@@ -772,14 +772,37 @@ SR_PRIV void agilent_54621d_send_logic_packet(struct sr_dev_inst *sdi,
if (!devc->logic_data)
return;
- logic.data = devc->logic_data->data;
- logic.length = devc->logic_data->len;
- logic.unitsize = devc->pod_count;
+ if(devc->num_blocks_downloaded == devc->trigger_at_sample/2000 && !devc->trigger_sent){
+ logic.data = devc->logic_data->data;
+ logic.length = devc->trigger_at_sample;
+ logic.unitsize = devc->pod_count;
+ packet.type = SR_DF_LOGIC;
+ packet.payload = &logic;
+ sr_session_send(sdi, &packet);
+
+ packet.type = SR_DF_TRIGGER;
+ packet.payload = NULL;
+ sr_session_send(sdi, &packet);
+ devc->trigger_sent = TRUE;
+
+ logic.data = devc->logic_data[devc->trigger_at_sample].data;
+ logic.length = devc->logic_data->len-devc->trigger_at_sample;
+ logic.unitsize = devc->pod_count;
+ packet.type = SR_DF_LOGIC;
+ packet.payload = &logic;
+ sr_session_send(sdi, &packet);
+ }
+ else
+ {
+ logic.data = devc->logic_data->data;
+ logic.length = devc->logic_data->len;
+ logic.unitsize = devc->pod_count;
- packet.type = SR_DF_LOGIC;
- packet.payload = &logic;
+ packet.type = SR_DF_LOGIC;
+ packet.payload = &logic;
- sr_session_send(sdi, &packet);
+ sr_session_send(sdi, &packet);
+ }
}
/* Undo previous resource allocation. */
@@ -815,6 +838,7 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
char command[MAX_COMMAND_SIZE];
float timebase_offset;
char *tmp_string;
+ int points_before_trigger;
tmp_string = NULL;
@@ -847,29 +871,75 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
}
devc->failcount=0;
- //Append downloaded block to buffer -- This should no longer be neccessary
- //g_byte_array_append(devc->buffer, data->data, data->len);
+ //if Trigger point is in this block
+ if(devc->num_blocks_downloaded == devc->trigger_at_sample/2000 && !devc->trigger_sent){
+ points_before_trigger = (int)(devc->trigger_at_sample - (devc->num_blocks_downloaded*2000));
+ sr_dbg("Handling trigger in analog package. Trigger at point: %d", points_before_trigger);
- sr_dbg("yRef: %d, yInc: %f, yOri: %f", info->yReference, info->yIncrement, info->yOrigin);
- for(i = 0; i<(int)data->len; i++){
- tmp_int=(int8_t)data->data[i];
- devc->data[i] = (((float)(tmp_int) - info->yReference) * info->yIncrement) + info->yOrigin;
+ for(i = 0; i<(int)points_before_trigger; i++){
+ tmp_int=(int8_t)data->data[i];
+ devc->data[i] = (((float)(tmp_int) - info->yReference) * info->yIncrement) + info->yOrigin;
+ }
+ if(points_before_trigger>0){
+ sr_analog_init(&analog, &encoding, &meaning, &spec, 2); //ToDo: 2 digits is just placeholder. needs to be calculated correctly
+ analog.meaning->channels = g_slist_append(NULL, ch);
+ analog.num_samples = points_before_trigger;
+ analog.data = devc->data;
+ analog.meaning->mq = SR_MQ_VOLTAGE;
+ analog.meaning->unit = SR_UNIT_VOLT;
+ analog.meaning->mqflags = 0;
+
+ packet.type = SR_DF_ANALOG;
+ packet.payload = &analog;
+ sr_session_send(sdi, &packet);
+
+ g_slist_free(analog.meaning->channels);
+ }
+
+ packet.type = SR_DF_TRIGGER;
+ packet.payload = NULL;
+ sr_session_send(sdi, &packet);
+ devc->trigger_sent = TRUE;
+
+ for(i = points_before_trigger; i<(int)data->len; i++){
+ tmp_int=(int8_t)data->data[i];
+ devc->data[i] = (((float)(tmp_int) - info->yReference) * info->yIncrement) + info->yOrigin;
+ }
+ sr_analog_init(&analog, &encoding, &meaning, &spec, 2); //ToDo: 2 digits is just placeholder. needs to be calculated correctly
+ analog.meaning->channels = g_slist_append(NULL, ch);
+ analog.num_samples = data->len-points_before_trigger;
+ analog.data = devc->data;
+ analog.meaning->mq = SR_MQ_VOLTAGE;
+ analog.meaning->unit = SR_UNIT_VOLT;
+ analog.meaning->mqflags = 0;
+
+ packet.type = SR_DF_ANALOG;
+ packet.payload = &analog;
+ sr_session_send(sdi, &packet);
+
+ g_slist_free(analog.meaning->channels);
+ }
+ else
+ {
+ for(i = 0; i<(int)data->len; i++){
+ tmp_int=(int8_t)data->data[i];
+ devc->data[i] = (((float)(tmp_int) - info->yReference) * info->yIncrement) + info->yOrigin;
+ }
+ sr_analog_init(&analog, &encoding, &meaning, &spec, 2); //ToDo: 2 digits is just placeholder. needs to be calculated correctly
+ analog.meaning->channels = g_slist_append(NULL, ch);
+ analog.num_samples = data->len;
+ analog.data = devc->data;
+ analog.meaning->mq = SR_MQ_VOLTAGE;
+ analog.meaning->unit = SR_UNIT_VOLT;
+ analog.meaning->mqflags = 0;
+
+ packet.type = SR_DF_ANALOG;
+ packet.payload = &analog;
+ sr_session_send(sdi, &packet);
+
+ g_slist_free(analog.meaning->channels);
}
- sr_analog_init(&analog, &encoding, &meaning, &spec, 2); //ToDo: 2 digits is just placeholder. needs to be calculated correctly
- analog.meaning->channels = g_slist_append(NULL, ch);
- analog.num_samples = data->len;
- analog.data = devc->data;
- analog.meaning->mq = SR_MQ_VOLTAGE;
- analog.meaning->unit = SR_UNIT_VOLT;
- analog.meaning->mqflags = 0;
-
- packet.type = SR_DF_ANALOG;
- packet.payload = &analog;
- sr_session_send(sdi, &packet);
-
- g_slist_free(analog.meaning->channels);
-
g_byte_array_free(data, TRUE);
data = NULL;
@@ -925,7 +995,7 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
if(devc->num_blocks_downloaded+1 < devc->num_block_to_download){
devc->num_blocks_downloaded++;
devc->current_channel = devc->enabled_channels;
- timebase_offset = devc->timebaseLbound+(devc->num_blocks_downloaded+0.5)*devc->block_deltaT;
+ timebase_offset = devc->timebaseLbound+(devc->num_blocks_downloaded-devc->refPos*0.1)*devc->block_deltaT;
sr_scpi_send(sdi->conn, ":TIM:DEL %f", timebase_offset);
sr_scpi_send(sdi->conn, ":SYST:DSP \"Reading Block %d/%d\"", devc->num_blocks_downloaded+1, devc->num_block_to_download);
//sr_scpi_send(sdi->conn, ":WAV:SOUR %s;DATA?", ((struct sr_channel *)devc->current_channel->data)->name);
diff --git a/src/hardware/agilent-54621d/protocol.h b/src/hardware/agilent-54621d/protocol.h
index 5c1fbcdef..31f41d6fc 100644
--- a/src/hardware/agilent-54621d/protocol.h
+++ b/src/hardware/agilent-54621d/protocol.h
@@ -164,6 +164,9 @@ struct dev_context {
float *data;
int failcount;
GByteArray *logic_data;
+ uint64_t trigger_at_sample;
+ gboolean trigger_sent;
+ int refPos;
};
SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data);
From 2fcd797b6d46926be6e239f564522b09e848bf7c Mon Sep 17 00:00:00 2001
From: Daniel <1824222@stud.hs-mannheim.de>
Date: Sat, 21 Jan 2023 14:37:44 +0100
Subject: [PATCH 7/9] minor fixes
---
src/hardware/agilent-54621d/api.c | 28 ++++++----------------------
1 file changed, 6 insertions(+), 22 deletions(-)
diff --git a/src/hardware/agilent-54621d/api.c b/src/hardware/agilent-54621d/api.c
index 2e806b1ec..2d89eeb9d 100644
--- a/src/hardware/agilent-54621d/api.c
+++ b/src/hardware/agilent-54621d/api.c
@@ -718,22 +718,13 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
if(devc->data_source == DATA_SOURCE_LIVE){
+ sr_scpi_get_bool(scpi, ":TER?", &tmp_bool);
sr_scpi_send(scpi, ":SING");
acq_complete = FALSE;
- for(i = 0; i device is stopped. This should be the case once the acquisition is complete
- acq_complete = TRUE;
- sr_dbg("Acquisition complete");
- break;
- }
+ sr_scpi_get_bool(scpi, ":TER?", &tmp_bool);
+ while(!tmp_bool){
g_usleep(WAIT_FOR_CAPTURE_COMPLETE_DELAY);
- if(agilent_54621d_update_sample_rate(sdi) != SR_OK)
- return SR_ERR;
- }
- if(!acq_complete){
- sr_err("Capture Timed out");
- return SR_ERR;
+ sr_scpi_get_bool(scpi, ":TER?", &tmp_bool);
}
} else if (devc->data_source == DATA_SOURCE_MEMORY) {
ch = (struct sr_channel *)devc->current_channel->data;
@@ -884,14 +875,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 100, agilent_54621d_receive_data, (void *)sdi);
- packet.type = SR_DF_HEADER;
- packet.payload = (uint8_t *)&header;
- header.feed_version = 1;
- header.starttime.tv_sec = 0;
- header.starttime.tv_usec = 1000000.0*devc->timebaseLbound;
- sr_dbg("Pretrigger time: %ld.", header.starttime.tv_usec);
- sr_session_send(sdi, &packet);
-
+ std_session_send_df_header(sdi);
//std_session_send_df_header(sdi);
std_session_send_df_frame_begin(sdi);
@@ -903,7 +887,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
return SR_OK;
-
+
}
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
From a680d90c51533bf348e556935a2d8f3caa8389e8 Mon Sep 17 00:00:00 2001
From: Daniel <1824222@stud.hs-mannheim.de>
Date: Sat, 21 Jan 2023 21:48:10 +0100
Subject: [PATCH 8/9] fixed potential memory leak
---
src/hardware/agilent-54621d/api.c | 60 +++++++++++---------------
src/hardware/agilent-54621d/protocol.c | 28 ++++++++----
src/hardware/agilent-54621d/protocol.h | 4 +-
3 files changed, 47 insertions(+), 45 deletions(-)
diff --git a/src/hardware/agilent-54621d/api.c b/src/hardware/agilent-54621d/api.c
index 2d89eeb9d..edc53512e 100644
--- a/src/hardware/agilent-54621d/api.c
+++ b/src/hardware/agilent-54621d/api.c
@@ -1,7 +1,7 @@
/*
* This file is part of the libsigrok project.
*
- * Copyright (C) 2022 Daniel <1824222@stud.hs-mannheim.de>
+ * Copyright (C) 2022 Daniel Echt
*
* 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
@@ -60,30 +60,6 @@ static const uint64_t samplerates[] = {
SR_HZ(1),
};
-static const uint64_t samplerates_literal[] = {
- SR_KHZ(2),
- SR_KHZ(4),
- SR_KHZ(5),
- SR_KHZ(10),
- SR_KHZ(20),
- SR_KHZ(40),
- SR_KHZ(50),
- SR_KHZ(100),
- SR_KHZ(200),
- SR_KHZ(400),
- SR_KHZ(500),
- SR_MHZ(1),
- SR_MHZ(2),
- SR_MHZ(4),
- SR_MHZ(5),
- SR_MHZ(10),
- SR_MHZ(20),
- SR_MHZ(25),
- SR_MHZ(50), //Can appear on device
- SR_MHZ(100), //Can appear on device
- SR_MHZ(200), //Can appear on device
-};
-
static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
{
struct sr_dev_inst *sdi;
@@ -137,6 +113,19 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return sr_scpi_scan(di->context, options, probe_device);
}
+static void clear_helper(struct dev_context *devc)
+{
+ agilent_54621d_scope_state_free(devc->model_state);
+ g_free(devc->analog_groups);
+ g_free(devc->digital_groups);
+ g_free(devc->data);
+}
+
+static int dev_clear(const struct sr_dev_driver *di)
+{
+ return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
+}
+
static int dev_open(struct sr_dev_inst *sdi)
{
int ret;
@@ -652,9 +641,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct sr_scpi_dev_inst *scpi;
struct scope_state *state;
const struct scope_config *model;
- int i;
int tmp_int;
- gboolean acq_complete;
gboolean tmp_bool;
char command[MAX_COMMAND_SIZE];
float xinc;
@@ -664,9 +651,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct analog_channel_transfer_info *encoding;
gboolean digital_added[MAX_DIGITAL_GROUP_COUNT];
size_t group, pod_count;
- struct sr_datafeed_packet packet;
- struct sr_datafeed_header header;
- struct timeval timeToTrigger;
scpi = sdi->conn;
@@ -720,7 +704,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
if(devc->data_source == DATA_SOURCE_LIVE){
sr_scpi_get_bool(scpi, ":TER?", &tmp_bool);
sr_scpi_send(scpi, ":SING");
- acq_complete = FALSE;
sr_scpi_get_bool(scpi, ":TER?", &tmp_bool);
while(!tmp_bool){
g_usleep(WAIT_FOR_CAPTURE_COMPLETE_DELAY);
@@ -747,13 +730,12 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
* The logic is, that if we want less than the complete waveform we can switch to window view, calculate the settings to have the window show exactly 2k points of the wv, and then transfer these 2k points.
* Then we can move the window delay and download the next 2k points. We can repeat this until we have the desired amount of points.
* This is also how the scope transfers the full waveform, however transfering the full wavefrom cannot be interrupted, so the manual approach is better
- * We save the number of samples already downloaded in devc->num_samples, and the samples themselves in devc->buffer until all data for a channel is ready
*/
//Reset parameters
devc->num_samples = 0;
devc->num_blocks_downloaded = 0;
- devc->buffer = g_malloc0(sizeof(char) * devc->samples_limit);
+ //devc->buffer = g_malloc0(sizeof(char) * devc->samples_limit);
devc->headerSent = FALSE;
//set waveform source channel to the first channel to be downloaded
@@ -812,7 +794,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
g_snprintf(command, sizeof(command), ":TIM:MODE MAIN;:TIM:RANG %f;:TIM:DEL %f", devc->block_deltaT, devc->timebaseLbound-devc->refPos*devc->block_deltaT*0.1);
sr_scpi_send(scpi, command);
- sr_dbg("Download %d packets with a width of %f. Maxpoints are %d. Lbound is %f. Trigger at sample %d", devc->num_block_to_download, devc->block_deltaT, points, devc->timebaseLbound, devc->trigger_at_sample);
+ sr_dbg("Download %d packets with a width of %f. Maxpoints are %d. Lbound is %f. Trigger at sample %ld", devc->num_block_to_download, devc->block_deltaT, points, devc->timebaseLbound, devc->trigger_at_sample);
sr_dbg("beginning data download");
//make final setup before download
@@ -897,6 +879,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
const struct scope_config *model;
struct scope_state *state;
float timebase;
+ struct sr_channel *ch;
devc = sdi->priv;
model = devc->model_config;
@@ -906,6 +889,13 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
timebase = (float) (*model->timebases)[state->timebase][0] / (*model->timebases)[state->timebase][1];
+ while(devc->current_channel){
+ ch = (struct sr_channel *)devc->current_channel->data;
+ if(ch->type == SR_CHANNEL_ANALOG)
+ g_free((struct analog_channel_transfer_info *)ch->priv);
+ devc->current_channel=devc->current_channel->next;
+ }
+
g_slist_free(devc->enabled_channels);
devc->enabled_channels = NULL;
scpi = sdi->conn;
@@ -924,7 +914,7 @@ static struct sr_dev_driver agilent_54621d_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
- .dev_clear = std_dev_clear,
+ .dev_clear = dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,
diff --git a/src/hardware/agilent-54621d/protocol.c b/src/hardware/agilent-54621d/protocol.c
index e66e6ad45..4c7f6edaa 100644
--- a/src/hardware/agilent-54621d/protocol.c
+++ b/src/hardware/agilent-54621d/protocol.c
@@ -1,7 +1,7 @@
/*
* This file is part of the libsigrok project.
*
- * Copyright (C) 2022 Daniel <1824222@stud.hs-mannheim.de>
+ * Copyright (C) 2022 Daniel Echt
*
* 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
@@ -29,6 +29,7 @@ SR_PRIV void agilent_54621d_cleanup_logic_data(struct dev_context *devc);
static struct scope_state *scope_state_new(const struct scope_config *config);
+
static int analog_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
static int digital_channel_state_get(struct sr_dev_inst *sdi, const struct scope_config *config, struct scope_state *state);
static int array_float_get(gchar *value, const uint64_t array[][2], int array_len, unsigned int *result);
@@ -136,7 +137,7 @@ static const char *trigger_sources[] = {
"DIG0", "DIG1", "DIG2", "DIG3", "DIG4", "DIG5", "DIG6", "DIG7", "DIG8", "DIG9", "DIG10", "DIG11", "DIG12", "DIG13", "DIG14", "DIG15",
};
-/* This is not currently used */
+/* This is not currently used. Does sigrok allow setting trigger mode?*/
static const char *trigger_mode[] = {
"EDGE",
"GLIT",
@@ -334,7 +335,6 @@ SR_PRIV int agilent_54621d_init_device(struct sr_dev_inst *sdi)
cg_name = (*scope_models[model_index].analog_names)[i];
devc->analog_groups[i] = sr_channel_group_new(sdi, cg_name, NULL);
devc->analog_groups[i]->channels = g_slist_append(NULL, ch);
- //devc->analog_groups[i]->priv = (void *)g_malloc0(sizeof(struct analog_channel_transfer_info));
}
/* Add digital channel groups. */
@@ -364,7 +364,11 @@ SR_PRIV int agilent_54621d_init_device(struct sr_dev_inst *sdi)
devc->samples_limit = 2000;
devc->frame_limit = 0;
devc->data_source = DATA_SOURCE_LIVE;
- devc->data = g_malloc(2000*sizeof(float));
+ devc->data = g_try_malloc0(2000*sizeof(float));
+
+ if(!devc->data)
+ return SR_ERR_MALLOC;
+
devc->sample_rate_limit = SR_MHZ(200);
if (!(devc->model_state = scope_state_new(devc->model_config)))
@@ -379,12 +383,20 @@ static struct scope_state *scope_state_new(const struct scope_config *config) {
state = g_malloc0(sizeof(struct scope_state));
state->analog_channels = g_malloc0_n(config->analog_channels, sizeof(struct analog_channel_state));
- state->digital_channels = g_malloc0_n(config->digital_channels, sizeof(gboolean) * MAX_DIGITAL_CHANNEL_COUNT); //ToDo: Why ony one bool size for the digital channel state? Shouldn't it be 1bool per channel?
+ state->digital_channels = g_malloc0_n(config->digital_channels, sizeof(gboolean) * MAX_DIGITAL_CHANNEL_COUNT);
state->digital_pods = g_malloc0_n(config->digital_pods, sizeof(struct digital_pod_state));
return state;
}
+SR_PRIV void agilent_54621d_scope_state_free(struct scope_state *state)
+{
+ g_free(state->analog_channels);
+ g_free(state->digital_channels);
+ g_free(state->digital_pods);
+ g_free(state);
+}
+
SR_PRIV int agilent_54621d_scope_state_get(struct sr_dev_inst *sdi)
{
struct dev_context *devc;
@@ -772,7 +784,7 @@ SR_PRIV void agilent_54621d_send_logic_packet(struct sr_dev_inst *sdi,
if (!devc->logic_data)
return;
- if(devc->num_blocks_downloaded == devc->trigger_at_sample/2000 && !devc->trigger_sent){
+ if((uint64_t)devc->num_blocks_downloaded == devc->trigger_at_sample/2000 && !devc->trigger_sent){
logic.data = devc->logic_data->data;
logic.length = devc->trigger_at_sample;
logic.unitsize = devc->pod_count;
@@ -872,7 +884,7 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
devc->failcount=0;
//if Trigger point is in this block
- if(devc->num_blocks_downloaded == devc->trigger_at_sample/2000 && !devc->trigger_sent){
+ if((uint64_t)devc->num_blocks_downloaded == devc->trigger_at_sample/2000 && !devc->trigger_sent){
points_before_trigger = (int)(devc->trigger_at_sample - (devc->num_blocks_downloaded*2000));
sr_dbg("Handling trigger in analog package. Trigger at point: %d", points_before_trigger);
@@ -992,7 +1004,7 @@ SR_PRIV int agilent_54621d_receive_data(int fd, int revents, void *cb_data)
//if more blocks need to be downloaded
sr_dbg("Downloaded %d/%d datablocks", devc->num_blocks_downloaded, devc->num_block_to_download);
- if(devc->num_blocks_downloaded+1 < devc->num_block_to_download){
+ if(devc->num_blocks_downloaded < devc->num_block_to_download){
devc->num_blocks_downloaded++;
devc->current_channel = devc->enabled_channels;
timebase_offset = devc->timebaseLbound+(devc->num_blocks_downloaded-devc->refPos*0.1)*devc->block_deltaT;
diff --git a/src/hardware/agilent-54621d/protocol.h b/src/hardware/agilent-54621d/protocol.h
index 31f41d6fc..94d2f4399 100644
--- a/src/hardware/agilent-54621d/protocol.h
+++ b/src/hardware/agilent-54621d/protocol.h
@@ -1,7 +1,7 @@
/*
* This file is part of the libsigrok project.
*
- * Copyright (C) 2022 Daniel <1824222@stud.hs-mannheim.de>
+ * Copyright (C) 2022 Daniel Echt
*
* 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
@@ -174,7 +174,7 @@ SR_PRIV int agilent_54621d_request_data(const struct sr_dev_inst *sdi);
SR_PRIV int agilent_54621d_init_device(struct sr_dev_inst *sdi);
SR_PRIV int agilent_54621d_scope_state_get(struct sr_dev_inst *sdi);
SR_PRIV int agilent_54621d_update_sample_rate(const struct sr_dev_inst *sdi);
+SR_PRIV void agilent_54621d_scope_state_free(struct scope_state *state);
-//static int wait_for_capture_complete(const struct sr_dev_inst *sdi);
#endif
From d4a779d6d4a59782792e28e00fc0e56b7ef1264c Mon Sep 17 00:00:00 2001
From: Daniel <1824222@stud.hs-mannheim.de>
Date: Sat, 21 Jan 2023 22:00:54 +0100
Subject: [PATCH 9/9] fixed scpi decoding for non standard responses to bool
requests
---
src/scpi/scpi.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/scpi/scpi.c b/src/scpi/scpi.c
index 6adcb0df6..fc710ee33 100644
--- a/src/scpi/scpi.c
+++ b/src/scpi/scpi.c
@@ -66,6 +66,7 @@ static int parse_strict_bool(const char *str, gboolean *ret)
*ret = TRUE;
return SR_OK;
} else if (!g_strcmp0(str, "0") ||
+ !g_strcmp0(str, "+0") ||
!g_ascii_strncasecmp(str, "n", 1) ||
!g_ascii_strncasecmp(str, "f", 1) ||
!g_ascii_strncasecmp(str, "no", 2) ||