From f91fb2a2b3664de43b27eab46bc9cd42cc022492 Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Thu, 27 Jun 2024 00:30:05 +0200 Subject: [PATCH 01/14] Added support for SDS2000X HD models based on the work of gralco (Eric Kuzmenko) in this PR : github.com/sigrokproject/libsigrok/pull/176/ Created a new protocol version "E11" matching the latest Siglent SDS Scope programming guide. Reduced the read-wait time from 7sec to 50ms for better performance (achived by looping on read sample logic to consume the data has it arrives). Tested with SDS2504X HD model connected via Ethernet cable. --- .gitignore | 1 + src/hardware/siglent-sds/api.c | 36 +- src/hardware/siglent-sds/protocol.c | 488 ++++++++++++++++++++++------ src/hardware/siglent-sds/protocol.h | 9 +- 4 files changed, 427 insertions(+), 107 deletions(-) diff --git a/.gitignore b/.gitignore index 235d51c2c..e183f1804 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,4 @@ stamp-h? /tests/*.log /tests/*.trs /tests/main +.vscode/ diff --git a/src/hardware/siglent-sds/api.c b/src/hardware/siglent-sds/api.c index 76955e6da..73bd15e77 100644 --- a/src/hardware/siglent-sds/api.c +++ b/src/hardware/siglent-sds/api.c @@ -171,6 +171,8 @@ enum series { SDS1000XP, SDS1000XE, SDS2000X, + SDS2000XP, + SDS2000XHD, }; /* short name, full name */ @@ -183,19 +185,23 @@ static const struct siglent_sds_vendor supported_vendors[] = { * number of vertical divs, live waveform samples, memory buffer samples */ static const struct siglent_sds_series supported_series[] = { [SDS1000CML] = {VENDOR(SIGLENT), "SDS1000CML", NON_SPO_MODEL, - { 50, 1 }, { 2, 1000 }, 18, 8, 1400363}, + { 50, 1 }, { 2, 1000 }, 18, 8, 25, 1400363}, [SDS1000CNL] = {VENDOR(SIGLENT), "SDS1000CNL", NON_SPO_MODEL, - { 50, 1 }, { 2, 1000 }, 18, 8, 1400363}, + { 50, 1 }, { 2, 1000 }, 18, 8, 25, 1400363}, [SDS1000DL] = {VENDOR(SIGLENT), "SDS1000DL", NON_SPO_MODEL, - { 50, 1 }, { 2, 1000 }, 18, 8, 1400363}, + { 50, 1 }, { 2, 1000 }, 18, 8, 25, 1400363}, [SDS1000X] = {VENDOR(SIGLENT), "SDS1000X", SPO_MODEL, - { 50, 1 }, { 500, 100000 }, 14, 8, 14000363}, + { 50, 1 }, { 500, 100000 }, 14, 8, 25, 14000363}, [SDS1000XP] = {VENDOR(SIGLENT), "SDS1000X+", SPO_MODEL, - { 50, 1 }, { 500, 100000 }, 14, 8, 14000363}, + { 50, 1 }, { 500, 100000 }, 14, 8, 25, 14000363}, [SDS1000XE] = {VENDOR(SIGLENT), "SDS1000XE", ESERIES, - { 50, 1 }, { 500, 100000 }, 14, 8, 14000363}, + { 50, 1 }, { 500, 100000 }, 14, 8, 25, 14000363}, [SDS2000X] = {VENDOR(SIGLENT), "SDS2000X", SPO_MODEL, - { 50, 1 }, { 500, 100000 }, 14, 8, 14000363}, + { 50, 1 }, { 500, 100000 }, 14, 8, 25, 14000363}, + [SDS2000XP] = {VENDOR(SIGLENT), "SDS2000X+", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + [SDS2000XHD] = {VENDOR(SIGLENT), "SDS2000XHD", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, }; #define SERIES(x) &supported_series[x] @@ -227,6 +233,15 @@ static const struct siglent_sds_model supported_models[] = { { SERIES(SDS2000X), "SDS2204X", { 2, 1000000000 }, 4, FALSE, 0 }, { SERIES(SDS2000X), "SDS2302X", { 2, 1000000000 }, 2, FALSE, 0 }, { SERIES(SDS2000X), "SDS2304X", { 2, 1000000000 }, 4, FALSE, 0 }, + { SERIES(SDS2000XP), "SDS2102X Plus", { 1, 1000000000 }, 2, TRUE, 16 }, + { SERIES(SDS2000XP), "SDS2104X Plus", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS2000XP), "SDS2204X Plus", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS2000XP), "SDS2354X Plus", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS2000XP), "SDS2504X Plus", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS2000XHD), "SDS2104X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS2000XHD), "SDS2204X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS2000XHD), "SDS2354X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS2000XHD), "SDS2504X HD", { 1, 1000000000 }, 4, TRUE, 16 }, }; static struct sr_dev_driver siglent_sds_driver_info; @@ -770,6 +785,7 @@ static int config_list(uint32_t key, GVariant **data, break; case SPO_MODEL: case ESERIES: + case E11: *data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources)); break; } @@ -860,7 +876,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) siglent_sds_get_dev_cfg_horizontal(sdi); switch (devc->model->series->protocol) { case SPO_MODEL: - if (siglent_sds_config_set(sdi, "WFSU SP,0,TYPE,1") != SR_OK) + case E11: + if (siglent_sds_config_set(sdi, "WFSU SP,0,NP,0,FP,0") != SR_OK) return SR_ERR; if (devc->average_enabled) { if (siglent_sds_config_set(sdi, "ACQW AVERAGE,%i", devc->average_samples) != SR_OK) @@ -881,7 +898,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) break; } - sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 7000, + int tiemout = (devc->model->series->protocol == E11) ? 50 : 7000; + sr_scpi_source_add(sdi->session, scpi, G_IO_IN, tiemout, siglent_sds_receive, (void *) sdi); std_session_send_df_header(sdi); diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index d59e52cbc..7f4d389c4 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -159,6 +159,7 @@ SR_PRIV int siglent_sds_capture_start(const struct sr_dev_inst *sdi) switch (devc->model->series->protocol) { case SPO_MODEL: + case E11: if (devc->data_source == DATA_SOURCE_SCREEN) { char *buf; int out; @@ -167,13 +168,22 @@ SR_PRIV int siglent_sds_capture_start(const struct sr_dev_inst *sdi) devc->num_frames + 1, devc->limit_frames); if (siglent_sds_config_set(sdi, "ARM") != SR_OK) return SR_ERR; + if (devc->model->series->protocol == E11) { + /* This pause is necessary for large memory depths. */ + struct sr_channel *ch = devc->channel_entry->data; + if (ch->type == SR_CHANNEL_ANALOG) { + float wait = devc->memory_depth_analog / 100; + sr_spew("Waiting %.f ms for the instrument to enter ARM mode.", wait / 1000); + g_usleep(wait); + } + } if (sr_scpi_get_string(sdi->conn, ":INR?", &buf) != SR_OK) return SR_ERR; sr_atoi(buf, &out); g_free(buf); - if (out == DEVICE_STATE_TRIG_RDY) { + if (out == DEVICE_STATE_TRIG_RDY || ((devc->model->series->protocol == E11) && (out == DEVICE_STATE_STOPPED))) { siglent_sds_set_wait_event(devc, WAIT_TRIGGER); - } else if (out == DEVICE_STATE_DATA_TRIG_RDY) { + } else if (out == DEVICE_STATE_DATA_TRIG_RDY || ((devc->model->series->protocol == E11) && (out == DEVICE_STATE_DATA_ACQ))) { sr_spew("Device triggered."); siglent_sds_set_wait_event(devc, WAIT_BLOCK); return SR_OK; @@ -288,6 +298,19 @@ SR_PRIV int siglent_sds_channel_start(const struct sr_dev_inst *sdi) return SR_ERR; siglent_sds_set_wait_event(devc, WAIT_NONE); break; + case E11: + if (ch->type == SR_CHANNEL_LOGIC) { + if (sr_scpi_send(sdi->conn, "WAV:SOUR D%d", ch->index) != SR_OK) + return SR_ERR; + } + else { + if (sr_scpi_send(sdi->conn, "WAV:SOUR C%d", ch->index + 1) != SR_OK) + return SR_ERR; + } + if (sr_scpi_send(sdi->conn, "WAV:PRE?") != SR_OK) + return SR_ERR; + siglent_sds_set_wait_event(devc, WAIT_NONE); + break; case ESERIES: if (ch->type == SR_CHANNEL_ANALOG) { if (sr_scpi_send(sdi->conn, "C%d:WF? ALL", @@ -304,6 +327,7 @@ SR_PRIV int siglent_sds_channel_start(const struct sr_dev_inst *sdi) devc->num_channel_bytes = 0; devc->num_header_bytes = 0; devc->num_block_bytes = 0; + devc->num_bytes_current_block = 0; return SR_OK; } @@ -315,12 +339,13 @@ static int siglent_sds_read_header(struct sr_dev_inst *sdi) struct dev_context *devc = sdi->priv; char *buf = (char *)devc->buffer; int ret, desc_length; - int block_offset = 15; /* Offset for descriptor block. */ + int block_offset = (devc->model->series->protocol == E11) ? 11 : 15; /* Offset for descriptor block. */ long data_length = 0; /* Read header from device. */ - ret = sr_scpi_read_data(scpi, buf, SIGLENT_HEADER_SIZE); - if (ret < SIGLENT_HEADER_SIZE) { + int header_size = (devc->model->series->protocol == E11) ? (SIGLENT_DIG_HEADER_SIZE+block_offset+1 /*+1 for 0x0A footer */) : SIGLENT_HEADER_SIZE; ; /* Size of the header, defined in wave_desc_length. */ + ret = sr_scpi_read_data(scpi, buf, header_size); + if (ret < header_size) { sr_err("Read error while reading data header."); return SR_ERR; } @@ -332,7 +357,7 @@ static int siglent_sds_read_header(struct sr_dev_inst *sdi) memcpy(&desc_length, buf + 36, 4); /* Descriptor block length */ memcpy(&data_length, buf + 60, 4); /* Data block length */ - devc->block_header_size = desc_length + 15; + devc->block_header_size = desc_length + block_offset; devc->num_samples = data_length; sr_dbg("Received data block header: '%s' -> block length %d.", buf, ret); @@ -340,100 +365,255 @@ static int siglent_sds_read_header(struct sr_dev_inst *sdi) return ret; } +static int siglent_sds_get_digital_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, uint8_t samplerate_ratio, GArray *data_low_channels, GArray *data_high_channels, gboolean* low_channels, gboolean* high_channels) +{ + uint8_t tmp_value; /* Holding temp value from data */ + GSList *l; + GArray *tmp_samplebuf; /* Temp buffer while iterating over the scope samples */ + GArray *buffdata; + gboolean first_pass = TRUE; + struct sr_scpi_dev_inst *scpi = sdi->conn; + struct dev_context *devc = sdi->priv; + int len = 0; + int channel_index = 0; + uint64_t samples_index; + for (l = sdi->channels; l; l = l->next) { + ch = l->data; + samples_index = 0; + if (ch->type == SR_CHANNEL_LOGIC) { + if (ch->enabled) { + do { + if (sr_scpi_read_begin(scpi) != SR_OK) + return TRUE; + if (sr_scpi_send(sdi->conn, "WAV:SOUR D%d", ch->index) != SR_OK) + return SR_ERR; + if (sr_scpi_send(sdi->conn, "WAV:STARt %d", devc->num_block_bytes) != SR_OK) + return SR_ERR; + if (sr_scpi_send(sdi->conn, "WAV:DATA?") != SR_OK) + return SR_ERR; + // TODO factorize consume header + /* Read header size : The header is of form “#9000001000” which nine ASCII integers are used to give the number of the waveform data points (1000 pts). */ + sr_scpi_read_data(scpi, (char *)devc->buffer, 2); + int headerSize = devc->buffer[1]-'0'; + /* Conume header */ + sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); + do { + len = sr_scpi_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); + if (len == -1 || len == 0) { + sr_err("Read error, aborting capture."); + std_session_send_df_frame_end(sdi); + sdi->driver->dev_acquisition_stop(sdi); + return TRUE; + } + devc->num_block_bytes += len; + devc->num_bytes_current_block += len; + // sr_dbg("Read %" PRIu64 " bytes, %" PRIu64 " remaining.",devc->num_bytes_current_block, devc->num_samples - devc->num_bytes_current_block); + } while (devc->num_bytes_current_block < devc->num_samples); + /* Consume 0x0A 0x0A message footer */ + uint16_t footer; + sr_scpi_read_data(scpi, (char *)&footer, 2); + + if (first_pass) + buffdata = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), devc->num_bytes_current_block); + g_array_append_vals(buffdata, (char *)(devc->buffer), devc->num_bytes_current_block); + + devc->num_block_read++; + devc->num_bytes_current_block = 0; + + if (first_pass) + tmp_samplebuf = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), devc->num_block_bytes*samplerate_ratio); /* New temp buffer. */ + first_pass = FALSE; + sr_err("Iterate on samples : number = %" PRIu64".",devc->num_block_bytes); + for (uint64_t cur_sample_index = 0; cur_sample_index < (unsigned)devc->num_block_bytes; cur_sample_index++) { + char sample = (char)g_array_index(buffdata, uint8_t, cur_sample_index); + for (int ii = 0; ii < 8; ii++, sample >>= 1) { + if (ch->index < 8) { + channel_index = ch->index; + if (data_low_channels->len <= samples_index) { + tmp_value = 0; /* New sample. */ + (*low_channels) = TRUE; /* We have at least one enabled low channel. */ + } else { + /* Get previous stored sample from low channel buffer. */ + tmp_value = g_array_index(data_low_channels, uint8_t, samples_index*samplerate_ratio); + } + } else { + channel_index = ch->index - 8; + if (data_high_channels->len <= samples_index) { + tmp_value = 0; /* New sample. */ + (*high_channels) = TRUE; /* We have at least one enabled high channel. */ + } else { + /* Get previous stored sample from high channel buffer. */ + tmp_value = g_array_index(data_high_channels, uint8_t, samples_index*samplerate_ratio); + } + } + /* Check if the current scope sample bit is set. */ + if (sample & 0x1) { + tmp_value |= (1UL << channel_index); /* Set current scope sample bit based on channel index. */ + } + + + g_array_append_val(tmp_samplebuf, tmp_value); + + /* SDS2000X+: Since the LA sample rate is a fraction of the sample rate of the analog channels, + * there needs to be repeated "fake" samples inserted after each "real" sample + * in order to make the output match the timebase of an enabled analog channel. + * The scaling by a factor of 2.5 and 5 appears to be necessary due to an artifact + * where the instrument will present half of the entire sample quantity from the screen + * within a single block (625000 bytes, or 5000000 bits / samples). Which means there + * are some legitimate points missing that are filled with "fake" ones at larger timebases. */ + for (int i = 0; i < samplerate_ratio-1; i++, ii++) + g_array_append_val(tmp_samplebuf, tmp_value); + + samples_index++; + } + } + } while (devc->num_block_bytes < devc->num_samples); + + /* Clear the buffers to prepare for the new samples */ + if (ch->index < 8) { + g_free(g_array_steal(data_low_channels,NULL)); + } else { + g_free(g_array_steal(data_high_channels,NULL)); + } + + /* Storing the converted temp values from the the scope into the buffers. */ + for (uint64_t index = 0; index < tmp_samplebuf->len; index++) { + uint8_t value = g_array_index(tmp_samplebuf, uint8_t, index); + if (ch->index < 8) + g_array_append_val(data_low_channels, value); + else + g_array_append_val(data_high_channels, value); + } + devc->num_block_bytes = 0; + g_free(g_array_steal(tmp_samplebuf, NULL)); + g_free(g_array_steal(buffdata, NULL)); + } + } + } + return len; +} + static int siglent_sds_get_digital(const struct sr_dev_inst *sdi, struct sr_channel *ch) { struct sr_scpi_dev_inst *scpi = sdi->conn; struct dev_context *devc = sdi->priv; - GArray *tmp_samplebuf; /* Temp buffer while iterating over the scope samples */ char *buf = (char *)devc->buffer; /* Buffer from scope */ - uint8_t tmp_value; /* Holding temp value from data */ - GArray *data_low_channels, *data_high_channels, *buffdata; - GSList *l; + GArray *data_low_channels, *data_high_channels; gboolean low_channels; /* Lower channels enabled */ gboolean high_channels; /* Higher channels enabled */ - int len, channel_index; + int len; uint64_t samples_index; + uint8_t samplerate_ratio = 1; + + if (devc->model->series->protocol == E11) { + /* Read Pre header */ + siglent_sds_read_header(sdi); + char *cmd; + float fvalue; + float digital_samplerate; + cmd = g_strdup_printf("DIG:SRAT?"); + int res = sr_scpi_get_float(sdi->conn, cmd, &fvalue); + g_free(cmd); + if (res != SR_OK) { + return SR_ERR; + } + digital_samplerate = (long)fvalue; + samplerate_ratio = devc->samplerate / (digital_samplerate / 8); + devc->memory_depth_digital = devc->memory_depth_digital / samplerate_ratio; + sr_dbg("Digital configuration : memory depth = %" PRIu64 ", sammple rate = %f, digital sample rate = %f, sample ratio = %d.", + devc->memory_depth_digital,devc->samplerate,digital_samplerate,samplerate_ratio); + } + len = 0; - channel_index = 0; low_channels = FALSE; high_channels = FALSE; data_low_channels = g_array_new(FALSE, TRUE, sizeof(uint8_t)); data_high_channels = g_array_new(FALSE, TRUE, sizeof(uint8_t)); - for (l = sdi->channels; l; l = l->next) { - ch = l->data; - samples_index = 0; - if (ch->type != SR_CHANNEL_LOGIC) - continue; - if (!ch->enabled) - continue; - if (sr_scpi_send(sdi->conn, "D%d:WF? DAT2", ch->index) != SR_OK) - return SR_ERR; - if (sr_scpi_read_begin(scpi) != SR_OK) - return TRUE; - len = sr_scpi_read_data(scpi, buf, -1); - if (len < 0) - return TRUE; - len -= 15; - buffdata = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), len); - buf += 15; /* Skipping the data header. */ - g_array_append_vals(buffdata, buf, len); - tmp_samplebuf = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), len); /* New temp buffer. */ - for (uint64_t cur_sample_index = 0; cur_sample_index < devc->memory_depth_digital; cur_sample_index++) { - char sample = (char)g_array_index(buffdata, uint8_t, cur_sample_index); - for (int ii = 0; ii < 8; ii++, sample >>= 1) { - if (ch->index < 8) { - channel_index = ch->index; - if (data_low_channels->len <= samples_index) { - tmp_value = 0; /* New sample. */ - low_channels = TRUE; /* We have at least one enabled low channel. */ - } else { - /* Get previous stored sample from low channel buffer. */ - tmp_value = g_array_index(data_low_channels, uint8_t, samples_index); - } - } else { - channel_index = ch->index - 8; - if (data_high_channels->len <= samples_index) { - tmp_value = 0; /* New sample. */ - high_channels = TRUE; /* We have at least one enabled high channel. */ + if(devc->model->series->protocol == E11) { + len = siglent_sds_get_digital_e11(sdi,ch,samplerate_ratio,data_low_channels,data_high_channels,&low_channels,&high_channels); + } + else { + uint8_t tmp_value; /* Holding temp value from data */ + GArray *tmp_samplebuf; /* Temp buffer while iterating over the scope samples */ + GSList *l; + GArray *buffdata; + int channel_index = 0; + for (l = sdi->channels; l; l = l->next) { + ch = l->data; + samples_index = 0; + if (ch->type != SR_CHANNEL_LOGIC) + continue; + if (!ch->enabled) + continue; + if (sr_scpi_send(sdi->conn, "D%d:WF? DAT2", ch->index) != SR_OK) + return SR_ERR; + if (sr_scpi_read_begin(scpi) != SR_OK) + return TRUE; + len = sr_scpi_read_data(scpi, buf, -1); + if (len < 0) + return TRUE; + len -= 15; + buffdata = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), len); + buf += 15; /* Skipping the data header. */ + g_array_append_vals(buffdata, buf, len); + tmp_samplebuf = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), len); /* New temp buffer. */ + for (uint64_t cur_sample_index = 0; cur_sample_index < devc->memory_depth_digital; cur_sample_index++) { + char sample = (char)g_array_index(buffdata, uint8_t, cur_sample_index); + for (int ii = 0; ii < 8; ii++, sample >>= 1) { + if (ch->index < 8) { + channel_index = ch->index; + if (data_low_channels->len <= samples_index) { + tmp_value = 0; /* New sample. */ + low_channels = TRUE; /* We have at least one enabled low channel. */ + } else { + /* Get previous stored sample from low channel buffer. */ + tmp_value = g_array_index(data_low_channels, uint8_t, samples_index); + } } else { - /* Get previous stored sample from high channel buffer. */ - tmp_value = g_array_index(data_high_channels, uint8_t, samples_index); + channel_index = ch->index - 8; + if (data_high_channels->len <= samples_index) { + tmp_value = 0; /* New sample. */ + high_channels = TRUE; /* We have at least one enabled high channel. */ + } else { + /* Get previous stored sample from high channel buffer. */ + tmp_value = g_array_index(data_high_channels, uint8_t, samples_index); + } } + /* Check if the current scope sample bit is set. */ + if (sample & 0x1) + tmp_value |= 1UL << channel_index; /* Set current scope sample bit based on channel index. */ + g_array_append_val(tmp_samplebuf, tmp_value); + samples_index++; } - /* Check if the current scope sample bit is set. */ - if (sample & 0x1) - tmp_value |= 1UL << channel_index; /* Set current scope sample bit based on channel index. */ - g_array_append_val(tmp_samplebuf, tmp_value); - samples_index++; } - } - /* Clear the buffers to prepare for the new samples */ - if (ch->index < 8) { - g_array_free(data_low_channels, TRUE); - data_low_channels = g_array_new(FALSE, FALSE, sizeof(uint8_t)); - } else { - g_array_free(data_high_channels, TRUE); - data_high_channels = g_array_new(FALSE, FALSE, sizeof(uint8_t)); - } + /* Clear the buffers to prepare for the new samples */ + if (ch->index < 8) { + g_array_free(data_low_channels, TRUE); + data_low_channels = g_array_new(FALSE, FALSE, sizeof(uint8_t)); + } else { + g_array_free(data_high_channels, TRUE); + data_high_channels = g_array_new(FALSE, FALSE, sizeof(uint8_t)); + } - /* Storing the converted temp values from the the scope into the buffers. */ - for (uint64_t index = 0; index < tmp_samplebuf->len; index++) { - uint8_t value = g_array_index(tmp_samplebuf, uint8_t, index); - if (ch->index < 8) - g_array_append_val(data_low_channels, value); - else - g_array_append_val(data_high_channels, value); + /* Storing the converted temp values from the the scope into the buffers. */ + for (uint64_t index = 0; index < tmp_samplebuf->len; index++) { + uint8_t value = g_array_index(tmp_samplebuf, uint8_t, index); + if (ch->index < 8) + g_array_append_val(data_low_channels, value); + else + g_array_append_val(data_high_channels, value); + } + g_array_free(tmp_samplebuf, TRUE); + g_array_free(buffdata, TRUE); } - g_array_free(tmp_samplebuf, TRUE); - g_array_free(buffdata, TRUE); } /* Combining the lower and higher channel buffers into one buffer for sigrok. */ devc->dig_buffer = g_array_new(FALSE, FALSE, sizeof(uint8_t)); - for (uint64_t index = 0; index < devc->memory_depth_digital; index++) { + for (uint64_t index = 0; index < devc->memory_depth_digital * samplerate_ratio; index++) { uint8_t value; if (low_channels) { value = g_array_index(data_low_channels, uint8_t, index); @@ -534,6 +714,10 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) sr_dbg("Waiting %.f0 ms for device to prepare the output buffers", wait / 1000); g_usleep(wait); break; + case E11: + if (sr_scpi_read_begin(scpi) != SR_OK) + return TRUE; + break; } sr_dbg("New block with header expected."); @@ -547,7 +731,9 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) sdi->driver->dev_acquisition_stop(sdi); return TRUE; } - devc->num_block_bytes = len; + if(devc->model->series->protocol != E11) { + devc->num_block_bytes = len; + } devc->num_block_read = 0; if (len == -1) { @@ -563,20 +749,44 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) /* We received all data as one block. */ /* Offset the data block buffer past the IEEE header and description header. */ devc->buffer += devc->block_header_size; - len = devc->num_samples; + devc->num_bytes_current_block = devc->num_samples; } else { - sr_dbg("Requesting: %" PRIu64 " bytes.", devc->num_samples - devc->num_block_bytes); - len = sr_scpi_read_data(scpi, (char *)devc->buffer, devc->num_samples-devc->num_block_bytes); - if (len == -1) { - sr_err("Read error, aborting capture."); - std_session_send_df_frame_end(sdi); - sdi->driver->dev_acquisition_stop(sdi); - return TRUE; + sr_dbg("Requesting: %" PRIu64 " bytes for %" PRIu64 " samples.", devc->num_samples - devc->num_block_bytes,devc->num_samples); + /* SDS2000X+ sends 10MB or 5MB blocks, as found by "WAV:MAXPoint?". */ + /* It needs to have the next starting point specified to continue. */ + if (devc->model->series->protocol == E11 && (devc->num_block_bytes == 0)) { + /*if (sr_scpi_send(sdi->conn, "WAV:SOUR C%d", ch->index + 1) != SR_OK) + return SR_ERR;*/ + /* TODO handle multiple blocks for E11 prtocol => use ACQuire:POINts? and WAVeform:MAXPoint? commands to get total points and points per block */ + if (sr_scpi_send(sdi->conn, "WAV:STARt %d", devc->num_block_bytes) != SR_OK) + return SR_ERR; + if (sr_scpi_send(sdi->conn, "WAV:DATA?") != SR_OK) + return SR_ERR; + /* Read header size : The header is of form “#9000001000” which nine ASCII integers are used to give the number of the waveform data points (1000 pts). */ + sr_scpi_read_data(scpi, (char *)devc->buffer, 2); + int headerSize = devc->buffer[1]-'0'; + /* Conume header */ + sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); + } + do { + len = sr_scpi_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); + if (len == -1 || len == 0) { + sr_err("Read error, aborting capture."); + std_session_send_df_frame_end(sdi); + sdi->driver->dev_acquisition_stop(sdi); + return TRUE; + } + devc->num_block_bytes += len; + devc->num_bytes_current_block += len; + sr_dbg("Read %" PRIu64 " bytes, %" PRIu64 " remaining.",devc->num_bytes_current_block, devc->num_samples - devc->num_bytes_current_block); + } while (devc->model->series->protocol == E11 && (devc->num_bytes_current_block < devc->num_samples)); + if(devc->model->series->protocol == E11) { + /* Consume 0x0A 0x0A message footer */ + uint16_t footer; + sr_scpi_read_data(scpi, (char *)&footer, 2); } - devc->num_block_read++; - devc->num_block_bytes += len; } - sr_dbg("Received block: %i, %d bytes.", devc->num_block_read, len); + sr_dbg("Received block: %i, %d bytes.", devc->num_block_read, devc->num_bytes_current_block); if (ch->type == SR_CHANNEL_ANALOG) { float vdiv = devc->vdiv[ch->index]; float offset = devc->vert_offset[ch->index]; @@ -585,11 +795,11 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) float voltage, vdivlog; int digits; - data = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), len); - g_array_append_vals(data, devc->buffer, len); + data = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), devc->num_bytes_current_block); + g_array_append_vals(data, devc->buffer, devc->num_bytes_current_block); float_data = g_array_new(FALSE, FALSE, sizeof(float)); - for (i = 0; i < len; i++) { - voltage = (float)g_array_index(data, int8_t, i) / 25; + for (i = 0; i < devc->num_bytes_current_block; i++) { + voltage = (float)g_array_index(data, int8_t, i) / devc->model->series->code_per_div; voltage = ((vdiv * voltage) - offset); g_array_append_val(float_data, voltage); } @@ -608,17 +818,23 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) g_slist_free(analog.meaning->channels); g_array_free(data, TRUE); } + devc->num_block_read++; + devc->num_bytes_current_block = 0; len = 0; - if (devc->num_samples == (devc->num_block_bytes - SIGLENT_HEADER_SIZE)) { + uint64_t bytes_to_read = devc->num_samples - ((devc->model->series->protocol == E11) ? (devc->num_block_bytes) : (devc->num_block_bytes - SIGLENT_HEADER_SIZE)); + sr_dbg("Total samples: %" PRIu64 "; bytes already read %" PRIu64 "; bytes left to read: %" PRIu64 " bytes.",devc->num_samples, devc->num_block_bytes, bytes_to_read); + if (bytes_to_read <= 0) { sr_dbg("Transfer has been completed."); devc->num_header_bytes = 0; devc->num_block_bytes = 0; read_complete = TRUE; if (!sr_scpi_read_complete(scpi)) { - sr_err("Read should have been completed."); - std_session_send_df_frame_end(sdi); - sdi->driver->dev_acquisition_stop(sdi); - return TRUE; + sr_err("Reading CH%d should have been completed.", ch->index + 1); + if (!devc->channel_entry->next) { + std_session_send_df_frame_end(sdi); + sdi->driver->dev_acquisition_stop(sdi); + return TRUE; + } } devc->num_block_read = 0; } else { @@ -741,7 +957,7 @@ SR_PRIV int siglent_sds_get_dev_cfg(const struct sr_dev_inst *sdi) } /* Timebase. */ - if (sr_scpi_get_float(sdi->conn, ":TDIV?", &devc->timebase) != SR_OK) + if (sr_scpi_get_double(sdi->conn, ":TDIV?", &devc->timebase) != SR_OK) return SR_ERR; sr_dbg("Current timebase: %g.", devc->timebase); @@ -915,6 +1131,12 @@ SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) } samplerate_scope = fvalue * 10000; } else { + sample_points_string[strlen(sample_points_string)] = '\0'; + if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { + sr_dbg("Invalid float converted from scope response."); + g_free(sample_points_string); + return SR_ERR; + } samplerate_scope = fvalue; } g_free(sample_points_string); @@ -933,10 +1155,82 @@ SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) } g_free(cmd); break; + case E11: { + double previous_timebase = devc->timebase; + /* Get the timebase. */ + if (sr_scpi_get_double(sdi->conn, ":TDIV?", &devc->timebase) != SR_OK) + return SR_ERR; + cmd = g_strdup_printf("SANU? C1"); + + /* SDS2000X+: If capturing from the display when the channels or timebase changed + * then quickly trigger and stop to get the correct memory depth. + * This is done due to the number of sample points not being updated after + * the after a channel is enabled/disabled or the timebase changes. */ + if (devc->data_source == DATA_SOURCE_SCREEN && + (devc->channels_switched || devc->timebase != previous_timebase)) { + if (sr_scpi_send(sdi->conn, "TRIG_MODE SINGLE") != SR_OK) + return SR_ERR; + res = sr_scpi_get_string(sdi->conn, cmd, &sample_points_string); + if (devc->la_enabled) { + cmd = g_strdup_printf("SANU? D0"); + if (sr_scpi_get_float(sdi->conn, cmd, &fvalue) != SR_OK) + return SR_ERR; + devc->memory_depth_digital = (long)fvalue; + } + if (sr_scpi_send(sdi->conn, ":TRIG:STOP") != SR_OK) + return SR_ERR; + devc->channels_switched = FALSE; + } + else { + res = sr_scpi_get_string(sdi->conn, cmd, &sample_points_string); + if (devc->la_enabled) { + cmd = g_strdup_printf("SANU? D0"); + if (sr_scpi_get_float(sdi->conn, cmd, &fvalue) != SR_OK) + return SR_ERR; + devc->memory_depth_digital = (long)fvalue; + } + } + g_free(cmd); + // TODO : refacto this part with SPO/NON-SPO models + samplerate_scope = 0; + fvalue = 0; + if (res != SR_OK) { + g_free(sample_points_string); + return SR_ERR; + } + if (g_strstr_len(sample_points_string, -1, "Mpts") != NULL) { + sample_points_string[strlen(sample_points_string) - 4] = '\0'; + if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { + sr_dbg("Invalid float converted from scope response."); + g_free(sample_points_string); + return SR_ERR; + } + samplerate_scope = fvalue * 1000000; + } else if (g_strstr_len(sample_points_string, -1, "Kpts") != NULL) { + sample_points_string[strlen(sample_points_string) - 4] = '\0'; + if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { + sr_dbg("Invalid float converted from scope response."); + g_free(sample_points_string); + return SR_ERR; + } + samplerate_scope = fvalue * 10000; + } else { + sample_points_string[strlen(sample_points_string)] = '\0'; + if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { + sr_dbg("Invalid float converted from scope response."); + g_free(sample_points_string); + return SR_ERR; + } + samplerate_scope = fvalue; + } + g_free(sample_points_string); + devc->memory_depth_analog = samplerate_scope; + break; + } }; /* Get the timebase. */ - if (sr_scpi_get_float(sdi->conn, ":TDIV?", &devc->timebase) != SR_OK) + if (sr_scpi_get_double(sdi->conn, ":TDIV?", &devc->timebase) != SR_OK) return SR_ERR; sr_dbg("Current timebase: %g.", devc->timebase); diff --git a/src/hardware/siglent-sds/protocol.h b/src/hardware/siglent-sds/protocol.h index 89abaf640..a38c9f7e0 100644 --- a/src/hardware/siglent-sds/protocol.h +++ b/src/hardware/siglent-sds/protocol.h @@ -49,6 +49,9 @@ enum protocol_version { SPO_MODEL, NON_SPO_MODEL, ESERIES, + // Refers to E11 Siglent Programming Guide : + // https://www.siglenteu.com/wp-content/uploads/dlm_uploads/2024/03/ProgrammingGuide_EN11F.pdf + E11, }; enum data_source { @@ -69,6 +72,7 @@ struct siglent_sds_series { uint64_t min_vdiv[2]; int num_horizontal_divs; int num_vertical_divs; + int code_per_div; int buffer_samples; }; @@ -120,7 +124,8 @@ struct dev_context { gboolean analog_channels[MAX_ANALOG_CHANNELS]; gboolean digital_channels[MAX_DIGITAL_CHANNELS]; gboolean la_enabled; - float timebase; + gboolean channels_switched; + double timebase; float attenuation[MAX_ANALOG_CHANNELS]; float vdiv[MAX_ANALOG_CHANNELS]; int vert_reference[MAX_ANALOG_CHANNELS]; @@ -143,6 +148,8 @@ struct dev_context { uint64_t num_header_bytes; /* Number of data blocks bytes already read. */ uint64_t num_block_bytes; + /* Number of data bytes already read in the current block. */ + uint64_t num_bytes_current_block; /* Number of data blocks read. */ int num_block_read; /* What to wait for in *_receive. */ From fa0a72a009e2053b4b1d1fa3cd5a4dc89674f6ef Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Thu, 4 Jul 2024 19:33:12 +0200 Subject: [PATCH 02/14] Added declaration of all E11 Siglent oscilocope series : 800X HD, 1000X HD, 3000X HD, 5000, 6000 and 7000. --- src/hardware/siglent-sds/api.c | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/hardware/siglent-sds/api.c b/src/hardware/siglent-sds/api.c index 73bd15e77..f6c3a75d5 100644 --- a/src/hardware/siglent-sds/api.c +++ b/src/hardware/siglent-sds/api.c @@ -172,7 +172,15 @@ enum series { SDS1000XE, SDS2000X, SDS2000XP, + SDS800XHD, + SDS1000XHD, SDS2000XHD, + SDS3000XHD, + SDS5000X, + SDS6000L, + SDS6000A, + SDS6000PRO, + SDS7000A, }; /* short name, full name */ @@ -200,8 +208,24 @@ static const struct siglent_sds_series supported_series[] = { { 50, 1 }, { 500, 100000 }, 14, 8, 25, 14000363}, [SDS2000XP] = {VENDOR(SIGLENT), "SDS2000X+", E11, { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + [SDS800XHD] = {VENDOR(SIGLENT), "SDS800XHD", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + [SDS1000XHD] = {VENDOR(SIGLENT), "SDS1000XHD", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, [SDS2000XHD] = {VENDOR(SIGLENT), "SDS2000XHD", E11, { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + [SDS3000XHD] = {VENDOR(SIGLENT), "SDS3000XHD", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + [SDS5000X] = {VENDOR(SIGLENT), "SDS5000X", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + [SDS6000L] = {VENDOR(SIGLENT), "SDS6000L", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + [SDS6000A] = {VENDOR(SIGLENT), "SDS6000A", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + [SDS6000PRO] = {VENDOR(SIGLENT), "SDS6000PRO", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + [SDS7000A] = {VENDOR(SIGLENT), "SDS7000A", E11, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, }; #define SERIES(x) &supported_series[x] @@ -238,10 +262,57 @@ static const struct siglent_sds_model supported_models[] = { { SERIES(SDS2000XP), "SDS2204X Plus", { 1, 1000000000 }, 4, TRUE, 16 }, { SERIES(SDS2000XP), "SDS2354X Plus", { 1, 1000000000 }, 4, TRUE, 16 }, { SERIES(SDS2000XP), "SDS2504X Plus", { 1, 1000000000 }, 4, TRUE, 16 }, + // SDS 800X HD Series + { SERIES(SDS800XHD), "SDS802X HD", { 1, 1000000000 }, 2, TRUE, 16 }, + { SERIES(SDS800XHD), "SDS804X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS800XHD), "SDS812X HD", { 1, 1000000000 }, 2, TRUE, 16 }, + { SERIES(SDS800XHD), "SDS814X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS800XHD), "SDS822X HD", { 1, 1000000000 }, 2, TRUE, 16 }, + { SERIES(SDS800XHD), "SDS824X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + // SDS 1000X HD Series + { SERIES(SDS1000XHD), "SDS1102X HD", { 1, 1000000000 }, 2, TRUE, 16 }, + { SERIES(SDS1000XHD), "SDS1104X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS1000XHD), "SDS1202X HD", { 1, 1000000000 }, 2, TRUE, 16 }, + { SERIES(SDS1000XHD), "SDS1204X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + // SDS 2000X HD Series { SERIES(SDS2000XHD), "SDS2104X HD", { 1, 1000000000 }, 4, TRUE, 16 }, { SERIES(SDS2000XHD), "SDS2204X HD", { 1, 1000000000 }, 4, TRUE, 16 }, { SERIES(SDS2000XHD), "SDS2354X HD", { 1, 1000000000 }, 4, TRUE, 16 }, { SERIES(SDS2000XHD), "SDS2504X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + // SDS 3000X HD Series + { SERIES(SDS3000XHD), "SDS3034X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS3000XHD), "SDS3054X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS3000XHD), "SDS3104X HD", { 1, 1000000000 }, 4, TRUE, 16 }, + // SDS 5000X Series + { SERIES(SDS5000X), "SDS5032X", { 1, 1000000000 }, 2, TRUE, 16 }, + { SERIES(SDS5000X), "SDS5034X", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS5000X), "SDS5052X", { 1, 1000000000 }, 2, TRUE, 16 }, + { SERIES(SDS5000X), "SDS5054X", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS5000X), "SDS5102X", { 1, 1000000000 }, 2, TRUE, 16 }, + { SERIES(SDS5000X), "SDS5104X", { 1, 1000000000 }, 4, TRUE, 16 }, + // SDS 6000L Series + { SERIES(SDS6000L), "SDS6208L", { 1, 1000000000 }, 8, TRUE, 16 }, + { SERIES(SDS6000L), "SDS6204L", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000L), "SDS6108L", { 1, 1000000000 }, 8, TRUE, 16 }, + { SERIES(SDS6000L), "SDS6104L", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000L), "SDS6058L", { 1, 1000000000 }, 8, TRUE, 16 }, + { SERIES(SDS6000L), "SDS6054L", { 1, 1000000000 }, 4, TRUE, 16 }, + // SDS 6000A Series + { SERIES(SDS6000A), "SDS6054A", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000A), "SDS6104A", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000A), "SDS6204A", { 1, 1000000000 }, 4, TRUE, 16 }, + // SDS 6000 Pro Series + { SERIES(SDS6000PRO), "SDS6034 H10 Pro", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000PRO), "SDS6034 H12 Pro", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000PRO), "SDS6054 H10 Pro", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000PRO), "SDS6054 H12 Pro", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000PRO), "SDS6104 H10 Pro", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000PRO), "SDS6104 H12 Pro", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000PRO), "SDS6204 H10 Pro", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS6000PRO), "SDS6204 H12 Pro", { 1, 1000000000 }, 4, TRUE, 16 }, + // SDS 7000A Series + { SERIES(SDS7000A), "SDS7404A", { 1, 1000000000 }, 4, TRUE, 16 }, + { SERIES(SDS7000A), "SDS7304A", { 1, 1000000000 }, 4, TRUE, 16 }, }; static struct sr_dev_driver siglent_sds_driver_info; From d47b871525dbcbdb4462efa2a17c9764efab7712 Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Wed, 17 Jul 2024 10:57:10 +0200 Subject: [PATCH 03/14] Added a timeout while reading data buffer to let time to the underlyling communication stack to get the data from the device. --- src/hardware/siglent-sds/protocol.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index 7f4d389c4..046bd3cf7 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -36,6 +36,31 @@ #include "scpi.h" #include "protocol.h" +/** Wait for 500 ms while reading SCPI data */ +#define WAIT_DATA_TIMEOUT 500000 + +/** + * Wait and read data from SCPI device. + * + * @param scpi Previously initialised SCPI device structure. + * @param buf Buffer to store result. + * @param maxlen Maximum number of bytes to read. + * + * @return Number of bytes read, or SR_ERR upon failure. + */ +static int siglent_scpi_wait_read_data(struct sr_scpi_dev_inst *scpi, + char *buf, int maxlen) +{ + int64_t start = g_get_monotonic_time(); + int64_t elapsed; + int ret; + do { + ret = sr_scpi_read_data(scpi, buf, maxlen); + elapsed = g_get_monotonic_time() - start; + } while ((ret == 0) && (elapsed < WAIT_DATA_TIMEOUT)); + return ret; +} + /* Set the next event to wait for in siglent_sds_receive(). */ static void siglent_sds_set_wait_event(struct dev_context *devc, enum wait_events event) { @@ -398,7 +423,7 @@ static int siglent_sds_get_digital_e11(struct sr_dev_inst *sdi, struct sr_channe /* Conume header */ sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); do { - len = sr_scpi_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); + len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); if (len == -1 || len == 0) { sr_err("Read error, aborting capture."); std_session_send_df_frame_end(sdi); @@ -769,7 +794,7 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); } do { - len = sr_scpi_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); + len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); if (len == -1 || len == 0) { sr_err("Read error, aborting capture."); std_session_send_df_frame_end(sdi); From f9419dfe15be9c1e8da1510a0b3b929ccd91bb67 Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Wed, 17 Jul 2024 17:27:48 +0200 Subject: [PATCH 04/14] Refactored code for better E11 modification isolation. --- src/hardware/siglent-sds/api.c | 2 +- src/hardware/siglent-sds/protocol.c | 98 ++++++++++++++--------------- 2 files changed, 47 insertions(+), 53 deletions(-) diff --git a/src/hardware/siglent-sds/api.c b/src/hardware/siglent-sds/api.c index f6c3a75d5..4b2aee07d 100644 --- a/src/hardware/siglent-sds/api.c +++ b/src/hardware/siglent-sds/api.c @@ -948,7 +948,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) switch (devc->model->series->protocol) { case SPO_MODEL: case E11: - if (siglent_sds_config_set(sdi, "WFSU SP,0,NP,0,FP,0") != SR_OK) + if (siglent_sds_config_set(sdi, ((devc->model->series->protocol == E11) ? "WFSU SP,0,NP,0,FP,0" : "WFSU SP,0,TYPE,1")) != SR_OK) return SR_ERR; if (devc->average_enabled) { if (siglent_sds_config_set(sdi, "ACQW AVERAGE,%i", devc->average_samples) != SR_OK) diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index 046bd3cf7..93832ef66 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -61,6 +61,46 @@ static int siglent_scpi_wait_read_data(struct sr_scpi_dev_inst *scpi, return ret; } +static int siglent_read_wave_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, gboolean digital) +{ + struct sr_scpi_dev_inst *scpi = sdi->conn; + struct dev_context *devc = sdi->priv; + int len = 0; + if(devc->num_block_bytes == 0) { + /* New block => send block request command */ + if(digital) { + /* PRE? command is not called on each Digital channel, so we need to set channel number here */ + if (sr_scpi_send(sdi->conn, "WAV:SOUR D%d", ch->index) != SR_OK) + return SR_ERR; + } + if (sr_scpi_send(sdi->conn, "WAV:STARt %d", devc->num_block_bytes) != SR_OK) + return SR_ERR; + if (sr_scpi_send(sdi->conn, "WAV:DATA?") != SR_OK) + return SR_ERR; + } + /* Read header size : The header is of form “#9000001000” which nine ASCII integers are used to give the number of the waveform data points (1000 pts). */ + sr_scpi_read_data(scpi, (char *)devc->buffer, 2); + int headerSize = devc->buffer[1]-'0'; + /* Conume header */ + sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); + do { + len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); + if (len == -1 || len == 0) { + sr_err("Read error, aborting capture."); + std_session_send_df_frame_end(sdi); + sdi->driver->dev_acquisition_stop(sdi); + return TRUE; + } + devc->num_block_bytes += len; + devc->num_bytes_current_block += len; + sr_dbg("Read %" PRIu64 " bytes, %" PRIu64 " remaining.",devc->num_bytes_current_block, devc->num_samples - devc->num_bytes_current_block); + } while (devc->num_bytes_current_block < devc->num_samples); + /* Consume 0x0A 0x0A message footer */ + uint16_t footer; + sr_scpi_read_data(scpi, (char *)&footer, 2); + return len; +} + /* Set the next event to wait for in siglent_sds_receive(). */ static void siglent_sds_set_wait_event(struct dev_context *devc, enum wait_events event) { @@ -410,33 +450,7 @@ static int siglent_sds_get_digital_e11(struct sr_dev_inst *sdi, struct sr_channe do { if (sr_scpi_read_begin(scpi) != SR_OK) return TRUE; - if (sr_scpi_send(sdi->conn, "WAV:SOUR D%d", ch->index) != SR_OK) - return SR_ERR; - if (sr_scpi_send(sdi->conn, "WAV:STARt %d", devc->num_block_bytes) != SR_OK) - return SR_ERR; - if (sr_scpi_send(sdi->conn, "WAV:DATA?") != SR_OK) - return SR_ERR; - // TODO factorize consume header - /* Read header size : The header is of form “#9000001000” which nine ASCII integers are used to give the number of the waveform data points (1000 pts). */ - sr_scpi_read_data(scpi, (char *)devc->buffer, 2); - int headerSize = devc->buffer[1]-'0'; - /* Conume header */ - sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); - do { - len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); - if (len == -1 || len == 0) { - sr_err("Read error, aborting capture."); - std_session_send_df_frame_end(sdi); - sdi->driver->dev_acquisition_stop(sdi); - return TRUE; - } - devc->num_block_bytes += len; - devc->num_bytes_current_block += len; - // sr_dbg("Read %" PRIu64 " bytes, %" PRIu64 " remaining.",devc->num_bytes_current_block, devc->num_samples - devc->num_bytes_current_block); - } while (devc->num_bytes_current_block < devc->num_samples); - /* Consume 0x0A 0x0A message footer */ - uint16_t footer; - sr_scpi_read_data(scpi, (char *)&footer, 2); + len = siglent_read_wave_e11(sdi,ch,TRUE); if (first_pass) buffdata = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), devc->num_bytes_current_block); @@ -777,38 +791,18 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) devc->num_bytes_current_block = devc->num_samples; } else { sr_dbg("Requesting: %" PRIu64 " bytes for %" PRIu64 " samples.", devc->num_samples - devc->num_block_bytes,devc->num_samples); - /* SDS2000X+ sends 10MB or 5MB blocks, as found by "WAV:MAXPoint?". */ - /* It needs to have the next starting point specified to continue. */ - if (devc->model->series->protocol == E11 && (devc->num_block_bytes == 0)) { - /*if (sr_scpi_send(sdi->conn, "WAV:SOUR C%d", ch->index + 1) != SR_OK) - return SR_ERR;*/ - /* TODO handle multiple blocks for E11 prtocol => use ACQuire:POINts? and WAVeform:MAXPoint? commands to get total points and points per block */ - if (sr_scpi_send(sdi->conn, "WAV:STARt %d", devc->num_block_bytes) != SR_OK) - return SR_ERR; - if (sr_scpi_send(sdi->conn, "WAV:DATA?") != SR_OK) - return SR_ERR; - /* Read header size : The header is of form “#9000001000” which nine ASCII integers are used to give the number of the waveform data points (1000 pts). */ - sr_scpi_read_data(scpi, (char *)devc->buffer, 2); - int headerSize = devc->buffer[1]-'0'; - /* Conume header */ - sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); + if(devc->model->series->protocol == E11) { + len = siglent_read_wave_e11(sdi,ch,FALSE); } - do { - len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); - if (len == -1 || len == 0) { + else { + len = sr_scpi_read_data(scpi, (char *)devc->buffer, devc->num_samples-devc->num_block_bytes); + if (len == -1) { sr_err("Read error, aborting capture."); std_session_send_df_frame_end(sdi); sdi->driver->dev_acquisition_stop(sdi); return TRUE; } devc->num_block_bytes += len; - devc->num_bytes_current_block += len; - sr_dbg("Read %" PRIu64 " bytes, %" PRIu64 " remaining.",devc->num_bytes_current_block, devc->num_samples - devc->num_bytes_current_block); - } while (devc->model->series->protocol == E11 && (devc->num_bytes_current_block < devc->num_samples)); - if(devc->model->series->protocol == E11) { - /* Consume 0x0A 0x0A message footer */ - uint16_t footer; - sr_scpi_read_data(scpi, (char *)&footer, 2); } } sr_dbg("Received block: %i, %d bytes.", devc->num_block_read, devc->num_bytes_current_block); From 253edb39317d2b5aa4d335f7d6da63b8e021dbe9 Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Thu, 18 Jul 2024 23:35:25 +0200 Subject: [PATCH 05/14] Refactored timebase detection code. Fixed compilation warnings. --- src/hardware/siglent-sds/protocol.c | 105 ++++++++++++---------------- 1 file changed, 43 insertions(+), 62 deletions(-) diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index 93832ef66..501618791 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -532,7 +532,7 @@ static int siglent_sds_get_digital_e11(struct sr_dev_inst *sdi, struct sr_channe return len; } -static int siglent_sds_get_digital(const struct sr_dev_inst *sdi, struct sr_channel *ch) +static int siglent_sds_get_digital(struct sr_dev_inst *sdi, struct sr_channel *ch) { struct sr_scpi_dev_inst *scpi = sdi->conn; struct dev_context *devc = sdi->priv; @@ -688,7 +688,8 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) struct sr_analog_spec spec; struct sr_datafeed_logic logic; struct sr_channel *ch; - int len, i; + int len; + uint64_t i; float wait; gboolean read_complete = FALSE; @@ -805,7 +806,7 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) devc->num_block_bytes += len; } } - sr_dbg("Received block: %i, %d bytes.", devc->num_block_read, devc->num_bytes_current_block); + sr_dbg("Received block: %i, %" PRIu64 " bytes.", devc->num_block_read, devc->num_bytes_current_block); if (ch->type == SR_CHANNEL_ANALOG) { float vdiv = devc->vdiv[ch->index]; float offset = devc->vert_offset[ch->index]; @@ -1111,6 +1112,39 @@ SR_PRIV int siglent_sds_get_dev_cfg_vertical(const struct sr_dev_inst *sdi) return SR_OK; } +static int siglent_parse_timebase(int read_result, char *sample_points_string, float* fvalue, float* samplerate_scope) +{ + if (read_result != SR_OK) { + return SR_ERR; + } + if (g_strstr_len(sample_points_string, -1, "Mpts") != NULL) { + sample_points_string[strlen(sample_points_string) - 4] = '\0'; + if (sr_atof_ascii(sample_points_string, fvalue) != SR_OK) { + sr_dbg("Invalid float converted from scope response."); + g_free(sample_points_string); + return SR_ERR; + } + *samplerate_scope = *fvalue * 1000000; + } else if (g_strstr_len(sample_points_string, -1, "Kpts") != NULL) { + sample_points_string[strlen(sample_points_string) - 4] = '\0'; + if (sr_atof_ascii(sample_points_string, fvalue) != SR_OK) { + sr_dbg("Invalid float converted from scope response."); + g_free(sample_points_string); + return SR_ERR; + } + *samplerate_scope = *fvalue * 10000; + } else { + sample_points_string[strlen(sample_points_string)] = '\0'; + if (sr_atof_ascii(sample_points_string, fvalue) != SR_OK) { + sr_dbg("Invalid float converted from scope response."); + g_free(sample_points_string); + return SR_ERR; + } + *samplerate_scope = *fvalue; + } + return SR_OK; +} + SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) { struct dev_context *devc; @@ -1129,36 +1163,10 @@ SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) g_free(cmd); samplerate_scope = 0; fvalue = 0; - if (res != SR_OK) { - g_free(sample_points_string); - return SR_ERR; - } - if (g_strstr_len(sample_points_string, -1, "Mpts") != NULL) { - sample_points_string[strlen(sample_points_string) - 4] = '\0'; - if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { - sr_dbg("Invalid float converted from scope response."); - g_free(sample_points_string); - return SR_ERR; - } - samplerate_scope = fvalue * 1000000; - } else if (g_strstr_len(sample_points_string, -1, "Kpts") != NULL) { - sample_points_string[strlen(sample_points_string) - 4] = '\0'; - if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { - sr_dbg("Invalid float converted from scope response."); - g_free(sample_points_string); - return SR_ERR; - } - samplerate_scope = fvalue * 10000; - } else { - sample_points_string[strlen(sample_points_string)] = '\0'; - if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { - sr_dbg("Invalid float converted from scope response."); - g_free(sample_points_string); - return SR_ERR; - } - samplerate_scope = fvalue; - } + res = siglent_parse_timebase(res,sample_points_string,&fvalue,&samplerate_scope); g_free(sample_points_string); + if (res != SR_OK) + return SR_ERR; devc->memory_depth_analog = samplerate_scope; break; case ESERIES: @@ -1210,39 +1218,12 @@ SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) } } g_free(cmd); - // TODO : refacto this part with SPO/NON-SPO models samplerate_scope = 0; fvalue = 0; - if (res != SR_OK) { - g_free(sample_points_string); - return SR_ERR; - } - if (g_strstr_len(sample_points_string, -1, "Mpts") != NULL) { - sample_points_string[strlen(sample_points_string) - 4] = '\0'; - if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { - sr_dbg("Invalid float converted from scope response."); - g_free(sample_points_string); - return SR_ERR; - } - samplerate_scope = fvalue * 1000000; - } else if (g_strstr_len(sample_points_string, -1, "Kpts") != NULL) { - sample_points_string[strlen(sample_points_string) - 4] = '\0'; - if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { - sr_dbg("Invalid float converted from scope response."); - g_free(sample_points_string); - return SR_ERR; - } - samplerate_scope = fvalue * 10000; - } else { - sample_points_string[strlen(sample_points_string)] = '\0'; - if (sr_atof_ascii(sample_points_string, &fvalue) != SR_OK) { - sr_dbg("Invalid float converted from scope response."); - g_free(sample_points_string); - return SR_ERR; - } - samplerate_scope = fvalue; - } + res = siglent_parse_timebase(res,sample_points_string,&fvalue,&samplerate_scope); g_free(sample_points_string); + if (res != SR_OK) + return SR_ERR; devc->memory_depth_analog = samplerate_scope; break; } From e91860d5ae36439bcc99ae4c870f17c1ff94721e Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Fri, 26 Jul 2024 23:07:52 +0200 Subject: [PATCH 06/14] Fixed block acquisition for E11 protocol => adds support for 4Mpts+ frames. --- src/hardware/siglent-sds/api.c | 14 +-- src/hardware/siglent-sds/protocol.c | 152 ++++++++++++++++------------ src/hardware/siglent-sds/protocol.h | 1 + 3 files changed, 95 insertions(+), 72 deletions(-) diff --git a/src/hardware/siglent-sds/api.c b/src/hardware/siglent-sds/api.c index 4b2aee07d..2db948a0b 100644 --- a/src/hardware/siglent-sds/api.c +++ b/src/hardware/siglent-sds/api.c @@ -213,19 +213,19 @@ static const struct siglent_sds_series supported_series[] = { [SDS1000XHD] = {VENDOR(SIGLENT), "SDS1000XHD", E11, { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, [SDS2000XHD] = {VENDOR(SIGLENT), "SDS2000XHD", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 100000000}, [SDS3000XHD] = {VENDOR(SIGLENT), "SDS3000XHD", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 400000000}, [SDS5000X] = {VENDOR(SIGLENT), "SDS5000X", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 250000000}, [SDS6000L] = {VENDOR(SIGLENT), "SDS6000L", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 500000000}, [SDS6000A] = {VENDOR(SIGLENT), "SDS6000A", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 500000000}, [SDS6000PRO] = {VENDOR(SIGLENT), "SDS6000PRO", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 500000000}, [SDS7000A] = {VENDOR(SIGLENT), "SDS7000A", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 500000000}, }; #define SERIES(x) &supported_series[x] diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index 501618791..318d880f6 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -66,25 +66,32 @@ static int siglent_read_wave_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, struct sr_scpi_dev_inst *scpi = sdi->conn; struct dev_context *devc = sdi->priv; int len = 0; - if(devc->num_block_bytes == 0) { - /* New block => send block request command */ - if(digital) { - /* PRE? command is not called on each Digital channel, so we need to set channel number here */ - if (sr_scpi_send(sdi->conn, "WAV:SOUR D%d", ch->index) != SR_OK) - return SR_ERR; - } - if (sr_scpi_send(sdi->conn, "WAV:STARt %d", devc->num_block_bytes) != SR_OK) - return SR_ERR; - if (sr_scpi_send(sdi->conn, "WAV:DATA?") != SR_OK) + int maxlen; + /* New block => send block request command */ + if(digital && (devc->num_block_read == 0)) { + /* PRE? command is not called on each Digital channel, so we need to set channel number here for first block*/ + if (sr_scpi_send(sdi->conn, "WAV:SOUR D%d", ch->index) != SR_OK) return SR_ERR; } + if (sr_scpi_send(sdi->conn, "WAV:STARt %d", devc->num_block_bytes) != SR_OK) + return SR_ERR; + if (sr_scpi_send(sdi->conn, "WAV:DATA?") != SR_OK) + return SR_ERR; /* Read header size : The header is of form “#9000001000” which nine ASCII integers are used to give the number of the waveform data points (1000 pts). */ sr_scpi_read_data(scpi, (char *)devc->buffer, 2); int headerSize = devc->buffer[1]-'0'; /* Conume header */ sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); + if(digital) { + /* For digital channel extract block size from header */ + devc->buffer[headerSize] = 0; + devc->max_points = atoi((char*)devc->buffer); + sr_dbg("Parsed data lengh from header '%s' : %f.",(char*)devc->buffer,devc->max_points); + } do { - len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + devc->num_bytes_current_block), devc->num_samples-devc->num_bytes_current_block); + /* Try and read end of block if not in last block or end of wave when in last block */ + maxlen = MIN(devc->num_samples-devc->num_block_bytes,devc->max_points-devc->num_bytes_current_block); + len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + devc->num_block_bytes), maxlen); if (len == -1 || len == 0) { sr_err("Read error, aborting capture."); std_session_send_df_frame_end(sdi); @@ -93,9 +100,10 @@ static int siglent_read_wave_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, } devc->num_block_bytes += len; devc->num_bytes_current_block += len; - sr_dbg("Read %" PRIu64 " bytes, %" PRIu64 " remaining.",devc->num_bytes_current_block, devc->num_samples - devc->num_bytes_current_block); - } while (devc->num_bytes_current_block < devc->num_samples); - /* Consume 0x0A 0x0A message footer */ + sr_dbg("Asked %d, read %" PRIu64 " bytes, %" PRIu64 " remaining.",maxlen,devc->num_block_bytes, devc->num_samples - devc->num_block_bytes); + } while ((devc->num_bytes_current_block < devc->max_points) && (devc->num_block_bytes < devc->num_samples)); + /* End of block or end of wave => consume 0x0A 0x0A message footer */ + sr_dbg("End of block => consume footer."); uint16_t footer; sr_scpi_read_data(scpi, (char *)&footer, 2); return len; @@ -367,13 +375,22 @@ SR_PRIV int siglent_sds_channel_start(const struct sr_dev_inst *sdi) if (ch->type == SR_CHANNEL_LOGIC) { if (sr_scpi_send(sdi->conn, "WAV:SOUR D%d", ch->index) != SR_OK) return SR_ERR; + /* WAV:PRE? is not working consistenly on SDS2000X HD (as for firmware 2.5.1.2.2.5) : + * For memory depth > 5 Mpoints it generates a SCPI response message stating "fp > current memory depth!". + * When only digital channels are activated, the WAV:PRE? response is longer than expected starting by + * "#9000000346WAVEDESC" but continuing after the 346's byte by a second ASCII message : + * "",DESC,#9000000346WAVEDESC". The data length specified in the first part is invalid + * The workaround is to not use the WAV:PRE? command and find the data length at the begenning + * of the WAV:DATA? response */ + devc->block_header_size = 0; + devc->num_samples = 0; } else { if (sr_scpi_send(sdi->conn, "WAV:SOUR C%d", ch->index + 1) != SR_OK) return SR_ERR; + if (sr_scpi_send(sdi->conn, "WAV:PRE?") != SR_OK) + return SR_ERR; } - if (sr_scpi_send(sdi->conn, "WAV:PRE?") != SR_OK) - return SR_ERR; siglent_sds_set_wait_event(devc, WAIT_NONE); break; case ESERIES: @@ -411,7 +428,9 @@ static int siglent_sds_read_header(struct sr_dev_inst *sdi) int header_size = (devc->model->series->protocol == E11) ? (SIGLENT_DIG_HEADER_SIZE+block_offset+1 /*+1 for 0x0A footer */) : SIGLENT_HEADER_SIZE; ; /* Size of the header, defined in wave_desc_length. */ ret = sr_scpi_read_data(scpi, buf, header_size); if (ret < header_size) { - sr_err("Read error while reading data header."); + sr_err("Read error while reading data header : received %d, expecred %d.",ret,header_size); + devc->block_header_size = 0; + devc->num_samples = 0; return SR_ERR; } sr_dbg("Device returned %i bytes.", ret); @@ -436,7 +455,6 @@ static int siglent_sds_get_digital_e11(struct sr_dev_inst *sdi, struct sr_channe GSList *l; GArray *tmp_samplebuf; /* Temp buffer while iterating over the scope samples */ GArray *buffdata; - gboolean first_pass = TRUE; struct sr_scpi_dev_inst *scpi = sdi->conn; struct dev_context *devc = sdi->priv; int len = 0; @@ -452,61 +470,59 @@ static int siglent_sds_get_digital_e11(struct sr_dev_inst *sdi, struct sr_channe return TRUE; len = siglent_read_wave_e11(sdi,ch,TRUE); - if (first_pass) - buffdata = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), devc->num_bytes_current_block); - g_array_append_vals(buffdata, (char *)(devc->buffer), devc->num_bytes_current_block); - devc->num_block_read++; devc->num_bytes_current_block = 0; - - if (first_pass) - tmp_samplebuf = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), devc->num_block_bytes*samplerate_ratio); /* New temp buffer. */ - first_pass = FALSE; - sr_err("Iterate on samples : number = %" PRIu64".",devc->num_block_bytes); - for (uint64_t cur_sample_index = 0; cur_sample_index < (unsigned)devc->num_block_bytes; cur_sample_index++) { - char sample = (char)g_array_index(buffdata, uint8_t, cur_sample_index); - for (int ii = 0; ii < 8; ii++, sample >>= 1) { - if (ch->index < 8) { - channel_index = ch->index; - if (data_low_channels->len <= samples_index) { - tmp_value = 0; /* New sample. */ - (*low_channels) = TRUE; /* We have at least one enabled low channel. */ - } else { - /* Get previous stored sample from low channel buffer. */ - tmp_value = g_array_index(data_low_channels, uint8_t, samples_index*samplerate_ratio); - } + } while (devc->num_block_bytes < devc->memory_depth_digital/* devc->num_samples*/); + + + buffdata = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), devc->num_block_bytes); + g_array_append_vals(buffdata, (char *)(devc->buffer), devc->num_block_bytes); + + tmp_samplebuf = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), devc->num_block_bytes*samplerate_ratio); /* New temp buffer. */ + sr_err("Iterate on samples : number = %" PRIu64".",devc->num_block_bytes); + for (uint64_t cur_sample_index = 0; cur_sample_index < (unsigned)devc->num_block_bytes; cur_sample_index++) { + char sample = (char)g_array_index(buffdata, uint8_t, cur_sample_index); + for (int ii = 0; ii < 8; ii++, sample >>= 1) { + if (ch->index < 8) { + channel_index = ch->index; + if (data_low_channels->len <= samples_index) { + tmp_value = 0; /* New sample. */ + (*low_channels) = TRUE; /* We have at least one enabled low channel. */ } else { - channel_index = ch->index - 8; - if (data_high_channels->len <= samples_index) { - tmp_value = 0; /* New sample. */ - (*high_channels) = TRUE; /* We have at least one enabled high channel. */ - } else { - /* Get previous stored sample from high channel buffer. */ - tmp_value = g_array_index(data_high_channels, uint8_t, samples_index*samplerate_ratio); - } + /* Get previous stored sample from low channel buffer. */ + tmp_value = g_array_index(data_low_channels, uint8_t, samples_index*samplerate_ratio); } - /* Check if the current scope sample bit is set. */ - if (sample & 0x1) { - tmp_value |= (1UL << channel_index); /* Set current scope sample bit based on channel index. */ + } else { + channel_index = ch->index - 8; + if (data_high_channels->len <= samples_index) { + tmp_value = 0; /* New sample. */ + (*high_channels) = TRUE; /* We have at least one enabled high channel. */ + } else { + /* Get previous stored sample from high channel buffer. */ + tmp_value = g_array_index(data_high_channels, uint8_t, samples_index*samplerate_ratio); } + } + /* Check if the current scope sample bit is set. */ + if (sample & 0x1) { + tmp_value |= (1UL << channel_index); /* Set current scope sample bit based on channel index. */ + } + + g_array_append_val(tmp_samplebuf, tmp_value); + /* SDS2000X+: Since the LA sample rate is a fraction of the sample rate of the analog channels, + * there needs to be repeated "fake" samples inserted after each "real" sample + * in order to make the output match the timebase of an enabled analog channel. + * The scaling by a factor of 2.5 and 5 appears to be necessary due to an artifact + * where the instrument will present half of the entire sample quantity from the screen + * within a single block (625000 bytes, or 5000000 bits / samples). Which means there + * are some legitimate points missing that are filled with "fake" ones at larger timebases. */ + for (int i = 0; i < samplerate_ratio-1; i++, ii++) g_array_append_val(tmp_samplebuf, tmp_value); - /* SDS2000X+: Since the LA sample rate is a fraction of the sample rate of the analog channels, - * there needs to be repeated "fake" samples inserted after each "real" sample - * in order to make the output match the timebase of an enabled analog channel. - * The scaling by a factor of 2.5 and 5 appears to be necessary due to an artifact - * where the instrument will present half of the entire sample quantity from the screen - * within a single block (625000 bytes, or 5000000 bits / samples). Which means there - * are some legitimate points missing that are filled with "fake" ones at larger timebases. */ - for (int i = 0; i < samplerate_ratio-1; i++, ii++) - g_array_append_val(tmp_samplebuf, tmp_value); - - samples_index++; - } + samples_index++; } - } while (devc->num_block_bytes < devc->num_samples); + } /* Clear the buffers to prepare for the new samples */ if (ch->index < 8) { @@ -524,6 +540,7 @@ static int siglent_sds_get_digital_e11(struct sr_dev_inst *sdi, struct sr_channe g_array_append_val(data_high_channels, value); } devc->num_block_bytes = 0; + devc->num_block_read = 0; g_free(g_array_steal(tmp_samplebuf, NULL)); g_free(g_array_steal(buffdata, NULL)); } @@ -546,8 +563,6 @@ static int siglent_sds_get_digital(struct sr_dev_inst *sdi, struct sr_channel *c uint8_t samplerate_ratio = 1; if (devc->model->series->protocol == E11) { - /* Read Pre header */ - siglent_sds_read_header(sdi); char *cmd; float fvalue; float digital_samplerate; @@ -560,6 +575,8 @@ static int siglent_sds_get_digital(struct sr_dev_inst *sdi, struct sr_channel *c digital_samplerate = (long)fvalue; samplerate_ratio = devc->samplerate / (digital_samplerate / 8); devc->memory_depth_digital = devc->memory_depth_digital / samplerate_ratio; + /* WAV:PRE? is not working consistenly on SDS2000X HD (as for firmware 2.5.1.2.2.5) => get the sample number form memory depth */ + devc->num_samples = devc->memory_depth_digital; sr_dbg("Digital configuration : memory depth = %" PRIu64 ", sammple rate = %f, digital sample rate = %f, sample ratio = %d.", devc->memory_depth_digital,devc->samplerate,digital_samplerate,samplerate_ratio); } @@ -1217,6 +1234,11 @@ SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) devc->memory_depth_digital = (long)fvalue; } } + + /* Get maximum number of point per data block */ + if (sr_scpi_get_double(sdi->conn, ":WAV:MAXP?", &devc->max_points) != SR_OK) + return SR_ERR; + g_free(cmd); samplerate_scope = 0; fvalue = 0; diff --git a/src/hardware/siglent-sds/protocol.h b/src/hardware/siglent-sds/protocol.h index a38c9f7e0..acee46d7f 100644 --- a/src/hardware/siglent-sds/protocol.h +++ b/src/hardware/siglent-sds/protocol.h @@ -126,6 +126,7 @@ struct dev_context { gboolean la_enabled; gboolean channels_switched; double timebase; + double max_points; float attenuation[MAX_ANALOG_CHANNELS]; float vdiv[MAX_ANALOG_CHANNELS]; int vert_reference[MAX_ANALOG_CHANNELS]; From 02fd7805c0eac653cb93220cd10d00b3d57130ee Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Sat, 27 Jul 2024 00:07:36 +0200 Subject: [PATCH 07/14] Fixed error detection when digital depth > 50Mpts --- src/hardware/siglent-sds/protocol.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index 318d880f6..01e6d71d9 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -79,6 +79,8 @@ static int siglent_read_wave_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, return SR_ERR; /* Read header size : The header is of form “#9000001000” which nine ASCII integers are used to give the number of the waveform data points (1000 pts). */ sr_scpi_read_data(scpi, (char *)devc->buffer, 2); + if(devc->buffer[0] != '#') + return SR_ERR; int headerSize = devc->buffer[1]-'0'; /* Conume header */ sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); @@ -469,10 +471,13 @@ static int siglent_sds_get_digital_e11(struct sr_dev_inst *sdi, struct sr_channe if (sr_scpi_read_begin(scpi) != SR_OK) return TRUE; len = siglent_read_wave_e11(sdi,ch,TRUE); + if (len < 0) { + return len; + } devc->num_block_read++; devc->num_bytes_current_block = 0; - } while (devc->num_block_bytes < devc->memory_depth_digital/* devc->num_samples*/); + } while (devc->num_block_bytes < devc->num_samples); buffdata = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), devc->num_block_bytes); @@ -589,6 +594,12 @@ static int siglent_sds_get_digital(struct sr_dev_inst *sdi, struct sr_channel *c if(devc->model->series->protocol == E11) { len = siglent_sds_get_digital_e11(sdi,ch,samplerate_ratio,data_low_channels,data_high_channels,&low_channels,&high_channels); + if (len < 0) { + sr_err("Read error, aborting capture."); + std_session_send_df_frame_end(sdi); + sdi->driver->dev_acquisition_stop(sdi); + return FALSE; + } } else { uint8_t tmp_value; /* Holding temp value from data */ @@ -811,6 +822,12 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) sr_dbg("Requesting: %" PRIu64 " bytes for %" PRIu64 " samples.", devc->num_samples - devc->num_block_bytes,devc->num_samples); if(devc->model->series->protocol == E11) { len = siglent_read_wave_e11(sdi,ch,FALSE); + if (len < 0) { + sr_err("Read error, aborting capture."); + std_session_send_df_frame_end(sdi); + sdi->driver->dev_acquisition_stop(sdi); + return TRUE; + } } else { len = sr_scpi_read_data(scpi, (char *)devc->buffer, devc->num_samples-devc->num_block_bytes); From 14ef9109bbf6ea4e677ab8836d971ead8c7fe8f5 Mon Sep 17 00:00:00 2001 From: fredzo Date: Thu, 1 Aug 2024 00:27:46 +0200 Subject: [PATCH 08/14] Fixed pagination for analog channels and digital channels. Read block length from block header for both analog and digital channels. Added use of WAV:POIN to specify block length as suggested in Siglent code exmaples. --- src/hardware/siglent-sds/protocol.c | 120 +++++++++++++++++++++------- src/hardware/siglent-sds/protocol.h | 2 +- 2 files changed, 92 insertions(+), 30 deletions(-) diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index 01e6d71d9..f9742f320 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -61,6 +61,51 @@ static int siglent_scpi_wait_read_data(struct sr_scpi_dev_inst *scpi, return ret; } +/** + * Get the number of points of the current wave and save it to devc->num_samples. + * + * @param sdi the device instance. + * @param devc the device context. + * + * @return SR_ERR upon failure. + */ +static int siglent_get_wave_points(struct sr_dev_inst *sdi,struct dev_context *devc) +{ + /* Get maximum number of point per data block */ + double acq_points; + int result = sr_scpi_get_double(sdi->conn, "ACQ:POIN?", &acq_points); + if(result == SR_OK) + devc->num_samples = acq_points; + return result; +} + +/** + * Get the number of points of the current digital channel and save it to devc->num_samples. + * + * @param sdi the device instance. + * @param devc the device context. + * + * @return SR_ERR upon failure. + */ +static int siglent_get_digital_points(struct sr_dev_inst *sdi,struct dev_context *devc) +{ + /* Get maximum number of point per data block */ + double dig_points; + int result = sr_scpi_get_double(sdi->conn, "DIG:POIN?", &dig_points); + if(result == SR_OK) + devc->num_samples = dig_points/8; /* 8 points per byte for digital channels */ + return result; +} + +/** + * Wait and read data from SCPI device. + * + * @param sdi the device instance. + * @param ch the channel. + * @param digital true for digital channels. + * + * @return Last number of bytes read, or SR_ERR upon failure. + */ static int siglent_read_wave_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, gboolean digital) { struct sr_scpi_dev_inst *scpi = sdi->conn; @@ -79,21 +124,32 @@ static int siglent_read_wave_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, return SR_ERR; /* Read header size : The header is of form “#9000001000” which nine ASCII integers are used to give the number of the waveform data points (1000 pts). */ sr_scpi_read_data(scpi, (char *)devc->buffer, 2); - if(devc->buffer[0] != '#') + if(devc->buffer[0] != '#') { + /* This is protocol error, consume any pending data before returning */ + sr_scpi_read_data(scpi, (char *)(devc->buffer+devc->num_block_bytes), (devc->model->series->buffer_samples-devc->num_block_bytes)); + if(digital) { + /* In digital mode, SDS 2000X HD (as for firmware 2.5.1.2.2.5) as a bug in block pagination : + * for memory depth > 50Mpts, if start point is >= to a certain value (625000 or 1250000) the DATA? command returns "DAT2,#9000000000" + * as a workaround, let's silently end acquisition at this point by filling the buffer with zeros */ + len = devc->num_samples-devc->num_block_bytes; + memset((char *)(devc->buffer+devc->num_block_bytes), 0, len); + devc->num_block_bytes = devc->num_samples; + return len; + } return SR_ERR; + } int headerSize = devc->buffer[1]-'0'; /* Conume header */ sr_scpi_read_data(scpi, (char *)devc->buffer, headerSize); - if(digital) { - /* For digital channel extract block size from header */ - devc->buffer[headerSize] = 0; - devc->max_points = atoi((char*)devc->buffer); - sr_dbg("Parsed data lengh from header '%s' : %f.",(char*)devc->buffer,devc->max_points); - } + /* Extract block size from header */ + devc->buffer[headerSize] = 0; + devc->max_points = atoi((char*)devc->buffer); + sr_dbg("Parsed data lengh from header '%s' : %d.",(char*)devc->buffer,devc->max_points); do { /* Try and read end of block if not in last block or end of wave when in last block */ maxlen = MIN(devc->num_samples-devc->num_block_bytes,devc->max_points-devc->num_bytes_current_block); - len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + devc->num_block_bytes), maxlen); + /* For analog channels, blocks are read one at a time, for digital all blocks are read in on buffer */ + len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + (digital ? devc->num_block_bytes : devc->num_bytes_current_block)), maxlen); if (len == -1 || len == 0) { sr_err("Read error, aborting capture."); std_session_send_df_frame_end(sdi); @@ -103,7 +159,7 @@ static int siglent_read_wave_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, devc->num_block_bytes += len; devc->num_bytes_current_block += len; sr_dbg("Asked %d, read %" PRIu64 " bytes, %" PRIu64 " remaining.",maxlen,devc->num_block_bytes, devc->num_samples - devc->num_block_bytes); - } while ((devc->num_bytes_current_block < devc->max_points) && (devc->num_block_bytes < devc->num_samples)); + } while ((devc->num_bytes_current_block < (uint64_t)devc->max_points) && (devc->num_block_bytes < devc->num_samples)); /* End of block or end of wave => consume 0x0A 0x0A message footer */ sr_dbg("End of block => consume footer."); uint16_t footer; @@ -441,13 +497,25 @@ static int siglent_sds_read_header(struct sr_dev_inst *sdi) /* Parse WaveDescriptor header. */ memcpy(&desc_length, buf + 36, 4); /* Descriptor block length */ - memcpy(&data_length, buf + 60, 4); /* Data block length */ - devc->block_header_size = desc_length + block_offset; - devc->num_samples = data_length; - - sr_dbg("Received data block header: '%s' -> block length %d.", buf, ret); + if(devc->model->series->protocol == E11) { + /* WAV:PRE? is not working consistenly on SDS2000X HD (as for firmware 2.5.1.2.2.5) => get the sample number ACQ:POIN? command */ + if(siglent_get_wave_points(sdi,devc) != SR_OK) { + sr_err("Read error while reading ACQ:POIN?."); + devc->num_samples = 0; + return SR_ERR; + } + if(devc->num_samples > (uint64_t)devc->max_points) { + /* We need to set block size to max_points*/ + if (sr_scpi_send(sdi->conn, "WAV:POINt %d", (int)devc->max_points) != SR_OK) + return SR_ERR; + } + } else { + memcpy(&data_length, buf + 60, 4); /* Data block length */ + devc->num_samples = data_length; + } + sr_dbg("Received data block header: '%s' -> header length = %d, data length = %" PRIu64 ".", buf, ret, devc->num_samples); return ret; } @@ -568,22 +636,15 @@ static int siglent_sds_get_digital(struct sr_dev_inst *sdi, struct sr_channel *c uint8_t samplerate_ratio = 1; if (devc->model->series->protocol == E11) { - char *cmd; - float fvalue; - float digital_samplerate; - cmd = g_strdup_printf("DIG:SRAT?"); - int res = sr_scpi_get_float(sdi->conn, cmd, &fvalue); - g_free(cmd); - if (res != SR_OK) { + /* Get num samples for digital channel */ + if(siglent_get_digital_points(sdi,devc) != SR_OK) { return SR_ERR; } - digital_samplerate = (long)fvalue; - samplerate_ratio = devc->samplerate / (digital_samplerate / 8); - devc->memory_depth_digital = devc->memory_depth_digital / samplerate_ratio; - /* WAV:PRE? is not working consistenly on SDS2000X HD (as for firmware 2.5.1.2.2.5) => get the sample number form memory depth */ - devc->num_samples = devc->memory_depth_digital; - sr_dbg("Digital configuration : memory depth = %" PRIu64 ", sammple rate = %f, digital sample rate = %f, sample ratio = %d.", - devc->memory_depth_digital,devc->samplerate,digital_samplerate,samplerate_ratio); + /* Set memory depth accordingly */ + devc->memory_depth_digital = devc->num_samples; + samplerate_ratio = devc->memory_depth_analog / devc->memory_depth_digital; + sr_dbg("Digital configuration : memory depth digital = %" PRIu64 ", memory depth analog = %" PRIu64 ", sample ratio = %d.", + devc->memory_depth_digital,devc->memory_depth_analog,samplerate_ratio); } len = 0; @@ -1253,8 +1314,9 @@ SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) } /* Get maximum number of point per data block */ - if (sr_scpi_get_double(sdi->conn, ":WAV:MAXP?", &devc->max_points) != SR_OK) + if (sr_scpi_get_int(sdi->conn, ":WAV:MAXP?", &devc->max_points) != SR_OK) return SR_ERR; + sr_dbg("Found maxp value of : %d.", devc->max_points); g_free(cmd); samplerate_scope = 0; diff --git a/src/hardware/siglent-sds/protocol.h b/src/hardware/siglent-sds/protocol.h index acee46d7f..ff684563e 100644 --- a/src/hardware/siglent-sds/protocol.h +++ b/src/hardware/siglent-sds/protocol.h @@ -126,7 +126,7 @@ struct dev_context { gboolean la_enabled; gboolean channels_switched; double timebase; - double max_points; + int max_points; float attenuation[MAX_ANALOG_CHANNELS]; float vdiv[MAX_ANALOG_CHANNELS]; int vert_reference[MAX_ANALOG_CHANNELS]; From e41e10f544f3f73387b729fba20977287a663ef2 Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Sun, 4 Aug 2024 23:11:49 +0200 Subject: [PATCH 09/14] Fixed triggering for large timebases by forcing stop mode before acquisition. Removed unused SCPI commands for E11 prtocol --- src/hardware/siglent-sds/api.c | 6 ++- src/hardware/siglent-sds/protocol.c | 70 +++++++++++------------------ 2 files changed, 29 insertions(+), 47 deletions(-) diff --git a/src/hardware/siglent-sds/api.c b/src/hardware/siglent-sds/api.c index 2db948a0b..7271c5c7c 100644 --- a/src/hardware/siglent-sds/api.c +++ b/src/hardware/siglent-sds/api.c @@ -947,8 +947,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) siglent_sds_get_dev_cfg_horizontal(sdi); switch (devc->model->series->protocol) { case SPO_MODEL: - case E11: - if (siglent_sds_config_set(sdi, ((devc->model->series->protocol == E11) ? "WFSU SP,0,NP,0,FP,0" : "WFSU SP,0,TYPE,1")) != SR_OK) + if (siglent_sds_config_set(sdi, "WFSU SP,0,TYPE,1") != SR_OK) return SR_ERR; if (devc->average_enabled) { if (siglent_sds_config_set(sdi, "ACQW AVERAGE,%i", devc->average_samples) != SR_OK) @@ -965,6 +964,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) if (siglent_sds_config_set(sdi, "ACQW SAMPLING") != SR_OK) return SR_ERR; break; + case E11: + /** TODO : handle acquisition mode (sampling / average) */ + break; default: break; } diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index f9742f320..a166d6ea3 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -290,7 +290,6 @@ SR_PRIV int siglent_sds_capture_start(const struct sr_dev_inst *sdi) switch (devc->model->series->protocol) { case SPO_MODEL: - case E11: if (devc->data_source == DATA_SOURCE_SCREEN) { char *buf; int out; @@ -299,22 +298,13 @@ SR_PRIV int siglent_sds_capture_start(const struct sr_dev_inst *sdi) devc->num_frames + 1, devc->limit_frames); if (siglent_sds_config_set(sdi, "ARM") != SR_OK) return SR_ERR; - if (devc->model->series->protocol == E11) { - /* This pause is necessary for large memory depths. */ - struct sr_channel *ch = devc->channel_entry->data; - if (ch->type == SR_CHANNEL_ANALOG) { - float wait = devc->memory_depth_analog / 100; - sr_spew("Waiting %.f ms for the instrument to enter ARM mode.", wait / 1000); - g_usleep(wait); - } - } if (sr_scpi_get_string(sdi->conn, ":INR?", &buf) != SR_OK) return SR_ERR; sr_atoi(buf, &out); g_free(buf); - if (out == DEVICE_STATE_TRIG_RDY || ((devc->model->series->protocol == E11) && (out == DEVICE_STATE_STOPPED))) { + if (out == DEVICE_STATE_TRIG_RDY) { siglent_sds_set_wait_event(devc, WAIT_TRIGGER); - } else if (out == DEVICE_STATE_DATA_TRIG_RDY || ((devc->model->series->protocol == E11) && (out == DEVICE_STATE_DATA_ACQ))) { + } else if (out == DEVICE_STATE_DATA_TRIG_RDY) { sr_spew("Device triggered."); siglent_sds_set_wait_event(devc, WAIT_BLOCK); return SR_OK; @@ -402,6 +392,24 @@ SR_PRIV int siglent_sds_capture_start(const struct sr_dev_inst *sdi) case NON_SPO_MODEL: siglent_sds_set_wait_event(devc, WAIT_TRIGGER); break; + case E11: { + char* buf; + /* Get maximum number of point per data block */ + if (sr_scpi_get_int(sdi->conn, "WAV:MAXP?", &devc->max_points) != SR_OK) + return SR_ERR; + sr_dbg("Found maxp value of : %d.", devc->max_points); + + /* Force trigger stop to make sure we have a consistant acquisition across channels */ + if (siglent_sds_config_set(sdi, "TRIG:STOP") != SR_OK) + return SR_ERR; + if (sr_scpi_get_string(sdi->conn, "TRIG:STAT?", &buf) != SR_OK) { + g_free(buf); + return SR_ERR; + } + g_free(buf); + siglent_sds_set_wait_event(devc, WAIT_BLOCK); + } + break; } return SR_OK; @@ -1278,46 +1286,18 @@ SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) g_free(cmd); break; case E11: { - double previous_timebase = devc->timebase; /* Get the timebase. */ if (sr_scpi_get_double(sdi->conn, ":TDIV?", &devc->timebase) != SR_OK) return SR_ERR; cmd = g_strdup_printf("SANU? C1"); - - /* SDS2000X+: If capturing from the display when the channels or timebase changed - * then quickly trigger and stop to get the correct memory depth. - * This is done due to the number of sample points not being updated after - * the after a channel is enabled/disabled or the timebase changes. */ - if (devc->data_source == DATA_SOURCE_SCREEN && - (devc->channels_switched || devc->timebase != previous_timebase)) { - if (sr_scpi_send(sdi->conn, "TRIG_MODE SINGLE") != SR_OK) - return SR_ERR; - res = sr_scpi_get_string(sdi->conn, cmd, &sample_points_string); - if (devc->la_enabled) { - cmd = g_strdup_printf("SANU? D0"); - if (sr_scpi_get_float(sdi->conn, cmd, &fvalue) != SR_OK) - return SR_ERR; - devc->memory_depth_digital = (long)fvalue; - } - if (sr_scpi_send(sdi->conn, ":TRIG:STOP") != SR_OK) + res = sr_scpi_get_string(sdi->conn, cmd, &sample_points_string); + if (devc->la_enabled) { + cmd = g_strdup_printf("SANU? D0"); + if (sr_scpi_get_float(sdi->conn, cmd, &fvalue) != SR_OK) return SR_ERR; - devc->channels_switched = FALSE; - } - else { - res = sr_scpi_get_string(sdi->conn, cmd, &sample_points_string); - if (devc->la_enabled) { - cmd = g_strdup_printf("SANU? D0"); - if (sr_scpi_get_float(sdi->conn, cmd, &fvalue) != SR_OK) - return SR_ERR; - devc->memory_depth_digital = (long)fvalue; - } + devc->memory_depth_digital = (long)fvalue; } - /* Get maximum number of point per data block */ - if (sr_scpi_get_int(sdi->conn, ":WAV:MAXP?", &devc->max_points) != SR_OK) - return SR_ERR; - sr_dbg("Found maxp value of : %d.", devc->max_points); - g_free(cmd); samplerate_scope = 0; fvalue = 0; From 8b7eccf8548793a63b77327cb271f54849b38cfb Mon Sep 17 00:00:00 2001 From: fredzo Date: Sat, 17 Aug 2024 22:02:58 +0200 Subject: [PATCH 10/14] Fixed pagination for digital channels. --- src/hardware/siglent-sds/protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index a166d6ea3..7ba304071 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -118,7 +118,7 @@ static int siglent_read_wave_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, if (sr_scpi_send(sdi->conn, "WAV:SOUR D%d", ch->index) != SR_OK) return SR_ERR; } - if (sr_scpi_send(sdi->conn, "WAV:STARt %d", devc->num_block_bytes) != SR_OK) + if (sr_scpi_send(sdi->conn, "WAV:STARt %d",digital ? (devc->num_block_bytes*8) : devc->num_block_bytes) != SR_OK) /* 8 points per byte in digital mode */ return SR_ERR; if (sr_scpi_send(sdi->conn, "WAV:DATA?") != SR_OK) return SR_ERR; From 07f991233bcbb6649bd9f26b57b09ff3c069deef Mon Sep 17 00:00:00 2001 From: fredzo Date: Sat, 17 Aug 2024 22:06:47 +0200 Subject: [PATCH 11/14] Fixed 500 micro-volt range for all models (there was a typo leading to 5mV instead of 500 uV). Fixed vertical ranges lower than 10mV for E11 models. --- src/hardware/siglent-sds/api.c | 57 ++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/hardware/siglent-sds/api.c b/src/hardware/siglent-sds/api.c index 7271c5c7c..412aa5e7c 100644 --- a/src/hardware/siglent-sds/api.c +++ b/src/hardware/siglent-sds/api.c @@ -106,7 +106,7 @@ static const uint64_t timebases[][2] = { static const uint64_t vdivs[][2] = { /* microvolts */ - { 500, 100000 }, + { 500, 1000000 }, /* millivolts */ { 1, 1000 }, { 2, 1000 }, @@ -199,33 +199,33 @@ static const struct siglent_sds_series supported_series[] = { [SDS1000DL] = {VENDOR(SIGLENT), "SDS1000DL", NON_SPO_MODEL, { 50, 1 }, { 2, 1000 }, 18, 8, 25, 1400363}, [SDS1000X] = {VENDOR(SIGLENT), "SDS1000X", SPO_MODEL, - { 50, 1 }, { 500, 100000 }, 14, 8, 25, 14000363}, + { 50, 1 }, { 500, 1000000 }, 14, 8, 25, 14000363}, [SDS1000XP] = {VENDOR(SIGLENT), "SDS1000X+", SPO_MODEL, - { 50, 1 }, { 500, 100000 }, 14, 8, 25, 14000363}, + { 50, 1 }, { 500, 1000000 }, 14, 8, 25, 14000363}, [SDS1000XE] = {VENDOR(SIGLENT), "SDS1000XE", ESERIES, - { 50, 1 }, { 500, 100000 }, 14, 8, 25, 14000363}, + { 50, 1 }, { 500, 1000000 }, 14, 8, 25, 14000363}, [SDS2000X] = {VENDOR(SIGLENT), "SDS2000X", SPO_MODEL, - { 50, 1 }, { 500, 100000 }, 14, 8, 25, 14000363}, + { 50, 1 }, { 500, 1000000 }, 14, 8, 25, 14000363}, [SDS2000XP] = {VENDOR(SIGLENT), "SDS2000X+", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 14000363}, [SDS800XHD] = {VENDOR(SIGLENT), "SDS800XHD", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 50000000}, [SDS1000XHD] = {VENDOR(SIGLENT), "SDS1000XHD", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 100000000}, [SDS2000XHD] = {VENDOR(SIGLENT), "SDS2000XHD", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 100000000}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 200000000}, [SDS3000XHD] = {VENDOR(SIGLENT), "SDS3000XHD", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 400000000}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 400000000}, [SDS5000X] = {VENDOR(SIGLENT), "SDS5000X", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 250000000}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 250000000}, [SDS6000L] = {VENDOR(SIGLENT), "SDS6000L", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 500000000}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 500000000}, [SDS6000A] = {VENDOR(SIGLENT), "SDS6000A", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 500000000}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 500000000}, [SDS6000PRO] = {VENDOR(SIGLENT), "SDS6000PRO", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 500000000}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 500000000}, [SDS7000A] = {VENDOR(SIGLENT), "SDS7000A", E11, - { 100, 1 }, { 500, 100000 }, 10, 8, 30, 500000000}, + { 100, 1 }, { 500, 1000000 }, 10, 8, 30, 500000000}, }; #define SERIES(x) &supported_series[x] @@ -714,17 +714,22 @@ static int config_set(uint32_t key, GVariant *data, if ((idx = std_u64_tuple_idx(data, ARRAY_AND_SIZE(vdivs))) < 0) return SR_ERR_ARG; devc->vdiv[i] = (float)vdivs[idx][0] / vdivs[idx][1]; - p = vdivs[idx][0]; - switch (vdivs[idx][1]) { - case 1: - cmd = g_strdup_printf("%" PRIu64 "V", p); - break; - case 1000: - cmd = g_strdup_printf("%" PRIu64 "MV", p); - break; - case 100000: - cmd = g_strdup_printf("%" PRIu64 "UV", p); - break; + if(devc->model->series->protocol == E11) { + /* E11 models don't support "MV" format for values bellow 10mV => switch to scientific format */ + cmd = g_strdup_printf("%.0E", devc->vdiv[i]); + } else { + p = vdivs[idx][0]; + switch (vdivs[idx][1]) { + case 1: + cmd = g_strdup_printf("%" PRIu64 "V", p); + break; + case 1000: + cmd = g_strdup_printf("%" PRIu64 "MV", p); + break; + case 100000: + cmd = g_strdup_printf("%" PRIu64 "UV", p); + break; + } } ret = siglent_sds_config_set(sdi, "C%d:VDIV %s", i + 1, cmd); g_free(cmd); From 8392ad30825aafdb304c1e80f92534f17f38e5d7 Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Fri, 11 Oct 2024 00:51:36 +0200 Subject: [PATCH 12/14] Fixed comment --- src/hardware/siglent-sds/protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index 7ba304071..16a4bea99 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -148,7 +148,7 @@ static int siglent_read_wave_e11(struct sr_dev_inst *sdi, struct sr_channel *ch, do { /* Try and read end of block if not in last block or end of wave when in last block */ maxlen = MIN(devc->num_samples-devc->num_block_bytes,devc->max_points-devc->num_bytes_current_block); - /* For analog channels, blocks are read one at a time, for digital all blocks are read in on buffer */ + /* For analog channels, blocks are read one at a time, for digital all blocks are read in one buffer */ len = siglent_scpi_wait_read_data(scpi, (char *)(devc->buffer + (digital ? devc->num_block_bytes : devc->num_bytes_current_block)), maxlen); if (len == -1 || len == 0) { sr_err("Read error, aborting capture."); From 0b9352aedc41cf48343c85af8963a02d3fdcd882 Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Fri, 11 Oct 2024 00:53:36 +0200 Subject: [PATCH 13/14] Fixed .vscode gitignore location --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e183f1804..a3f055be0 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ .*.sw* /*.kdev4 /Makefile.am.user +.vscode/ # clangd language server cruft .cache/ @@ -80,4 +81,3 @@ stamp-h? /tests/*.log /tests/*.trs /tests/main -.vscode/ From aa9b2184d5353defb1a17db81a70c718ca932ab5 Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Fri, 11 Oct 2024 00:56:54 +0200 Subject: [PATCH 14/14] Fixed microvolt multiplier. --- src/hardware/siglent-sds/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/siglent-sds/api.c b/src/hardware/siglent-sds/api.c index 412aa5e7c..c4465a3c3 100644 --- a/src/hardware/siglent-sds/api.c +++ b/src/hardware/siglent-sds/api.c @@ -726,7 +726,7 @@ static int config_set(uint32_t key, GVariant *data, case 1000: cmd = g_strdup_printf("%" PRIu64 "MV", p); break; - case 100000: + case 1000000: cmd = g_strdup_printf("%" PRIu64 "UV", p); break; }