diff --git a/src/hardware/siglent-sds/api.c b/src/hardware/siglent-sds/api.c index 76955e6da..2536acbd0 100644 --- a/src/hardware/siglent-sds/api.c +++ b/src/hardware/siglent-sds/api.c @@ -171,6 +171,7 @@ enum series { SDS1000XP, SDS1000XE, SDS2000X, + SDS2000XP, }; /* short name, full name */ @@ -183,19 +184,21 @@ 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+", SPO_MODEL, + { 100, 1 }, { 500, 100000 }, 10, 8, 30, 14000363}, }; #define SERIES(x) &supported_series[x] @@ -227,6 +230,11 @@ 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 }, }; static struct sr_dev_driver siglent_sds_driver_info; @@ -429,6 +437,36 @@ static int config_get(uint32_t key, GVariant **data, *data = g_variant_new_string("History"); break; case SR_CONF_SAMPLERATE: + /* SDS2000X+: The channels need to be enabled/disabled prior to + * obtaining the sample rate when the data source is set to display. + * If a channel is turned on/off on the oscilloscope then use Sigrok's settings instead. */ + if (!strcmp(devc->model->series->name, "SDS2000X+") && devc->data_source == DATA_SOURCE_SCREEN) { + GSList *l; + for (l = sdi->channels; l; l = l->next) { + ch = l->data; + if (ch->type == SR_CHANNEL_ANALOG) { + char *channel_state; + char *cmd = g_strdup_printf("C%d:TRA?", ch->index + 1); + sr_scpi_get_string(sdi->conn, cmd, &channel_state); + if (!strcmp(channel_state, "ON") && !ch->enabled) + if (siglent_sds_config_set(sdi, "C%d:TRA %s", ch->index + 1, + ch->enabled ? "ON" : "OFF") != SR_OK) + return SR_ERR; + if (!strcmp(channel_state, "OFF") && ch->enabled) + if (siglent_sds_config_set(sdi, "C%d:TRA %s", ch->index + 1, + ch->enabled ? "ON" : "OFF") != SR_OK) + return SR_ERR; + if (ch->enabled != devc->analog_channels[ch->index]) { + /* Enabled channel is currently disabled, or vice versa. */ + if (siglent_sds_config_set(sdi, "C%d:TRA %s", ch->index + 1, + ch->enabled ? "ON" : "OFF") != SR_OK) + return SR_ERR; + devc->analog_channels[ch->index] = ch->enabled; + devc->channels_switched = TRUE; + } + } + } + } siglent_sds_get_dev_cfg_horizontal(sdi); *data = g_variant_new_uint64(devc->samplerate); break; @@ -857,10 +895,12 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) // devc->analog_frame_size = devc->model->series->buffer_samples; // devc->digital_frame_size = devc->model->series->buffer_samples; - siglent_sds_get_dev_cfg_horizontal(sdi); + if (strcmp(devc->model->series->name, "SDS2000X+")) + siglent_sds_get_dev_cfg_horizontal(sdi); + siglent_sds_get_dev_cfg_vertical(sdi); switch (devc->model->series->protocol) { case SPO_MODEL: - if (siglent_sds_config_set(sdi, "WFSU SP,0,TYPE,1") != SR_OK) + 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) diff --git a/src/hardware/siglent-sds/protocol.c b/src/hardware/siglent-sds/protocol.c index d59e52cbc..7df2d931f 100644 --- a/src/hardware/siglent-sds/protocol.c +++ b/src/hardware/siglent-sds/protocol.c @@ -167,11 +167,18 @@ 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; + /* 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 || out == DEVICE_STATE_STOPPED) { siglent_sds_set_wait_event(devc, WAIT_TRIGGER); } else if (out == DEVICE_STATE_DATA_TRIG_RDY) { sr_spew("Device triggered."); @@ -283,9 +290,23 @@ SR_PRIV int siglent_sds_channel_start(const struct sr_dev_inst *sdi) switch (devc->model->series->protocol) { case NON_SPO_MODEL: case SPO_MODEL: - s = (ch->type == SR_CHANNEL_LOGIC) ? "D%d:WF?" : "C%d:WF? ALL"; - if (sr_scpi_send(sdi->conn, s, ch->index + 1) != SR_OK) - return SR_ERR; + if (!strcmp(devc->model->series->name, "SDS2000X+")) { + 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; + } + else { + s = (ch->type == SR_CHANNEL_LOGIC) ? "D%d:WF?" : "C%d:WF? ALL"; + if (sr_scpi_send(sdi->conn, s, ch->index + 1) != SR_OK) + return SR_ERR; + } siglent_sds_set_wait_event(devc, WAIT_NONE); break; case ESERIES: @@ -315,13 +336,25 @@ 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; /* Offset for descriptor block. */ + if (!strcmp(devc->model->series->name, "SDS2000X+")) + block_offset = 11; + else + block_offset = 15; + long data_length = 0; + int header_size; /* Size of the header, defined in wave_desc_length. */ + if (!strcmp(devc->model->series->name, "SDS2000X+")) + header_size = SIGLENT_DIG_HEADER_SIZE; + else + header_size = SIGLENT_HEADER_SIZE; + /* Read header from device. */ - ret = sr_scpi_read_data(scpi, buf, SIGLENT_HEADER_SIZE); - if (ret < SIGLENT_HEADER_SIZE) { + ret = sr_scpi_read_data(scpi, buf, header_size); + if (ret < header_size) { sr_err("Read error while reading data header."); + sr_dbg("Device returned %i bytes.", ret); return SR_ERR; } sr_dbg("Device returned %i bytes.", ret); @@ -332,7 +365,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); @@ -354,6 +387,20 @@ static int siglent_sds_get_digital(const struct sr_dev_inst *sdi, struct sr_chan int len, channel_index; uint64_t samples_index; + uint8_t samplerate_ratio = 1; + + if (!strcmp(devc->model->series->name, "SDS2000X+")) { + char *cmd; + float fvalue; + float digital_samplerate; + cmd = g_strdup_printf("DI:SARA?"); + if (sr_scpi_get_float(sdi->conn, cmd, &fvalue) != SR_OK) + return SR_ERR; + digital_samplerate = (long)fvalue; + samplerate_ratio = devc->samplerate / digital_samplerate; + devc->memory_depth_digital = devc->memory_depth_digital / (8 * samplerate_ratio); + } + len = 0; channel_index = 0; low_channels = FALSE; @@ -364,76 +411,127 @@ static int siglent_sds_get_digital(const struct sr_dev_inst *sdi, struct sr_chan 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); + if (ch->type == SR_CHANNEL_LOGIC) { + if (ch->enabled) { + gboolean first_pass = TRUE; + do { + if (!strcmp(devc->model->series->name, "SDS2000X+")) { + 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; + sr_scpi_read_data(scpi, buf, 11); } - } 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 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, devc->memory_depth_digital-devc->num_block_bytes); + if (len < 0) + return TRUE; + /* SDS2000X+: Throw away the last two 0A 0A bytes for full blocks. */ + if (!strcmp(devc->model->series->name, "SDS2000X+") && len == 625002) + len -= 2; + if (strcmp(devc->model->series->name, "SDS2000X+")) + len -= 15; + devc->num_block_bytes += len; + if (first_pass) + buffdata = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), len); + if (strcmp(devc->model->series->name, "SDS2000X+")) + buf += 15; /* Skipping the data header. */ + g_array_append_vals(buffdata, buf, len); + + /* SDS2000X+: As of firmware version 1.3.9R6 the WAVeform:STARt command + * seems to be ignored for digital channels. Therefore, all blocks after the first + * one are discarded. */ + if (!strcmp(devc->model->series->name, "SDS2000X+") && first_pass && devc->memory_depth_digital > (unsigned)len) + if (devc->memory_depth_digital / len >= 2) + devc->memory_depth_digital = len; + + if (first_pass) + tmp_samplebuf = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), len*samplerate_ratio); /* New temp buffer. */ + for (uint64_t cur_sample_index = 0; cur_sample_index < (unsigned)len; 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. */ + } 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); + + /* 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. */ + if (!strcmp(devc->model->series->name, "SDS2000X+")) { + if (devc->memory_depth_digital / (float)len == 2.5) + samplerate_ratio *= 2.5; + else if (devc->memory_depth_digital / len == 5) + samplerate_ratio *= 5; + for (int i = 0; i < samplerate_ratio-1; i++, samples_index++) + g_array_append_val(tmp_samplebuf, tmp_value); + if (devc->memory_depth_digital / (float)len == 2.5) + samplerate_ratio /= 2.5; + else if (devc->memory_depth_digital / len == 5) + samplerate_ratio /= 5; + } + samples_index++; + } + } + + /* Clear the buffers to prepare for the new samples */ + if (ch->index < 8) { + g_array_free(data_low_channels, FALSE); + data_low_channels = g_array_new(FALSE, FALSE, sizeof(uint8_t)); } else { - /* Get previous stored sample from high channel buffer. */ - tmp_value = g_array_index(data_high_channels, uint8_t, samples_index); + g_array_free(data_high_channels, FALSE); + data_high_channels = g_array_new(FALSE, FALSE, sizeof(uint8_t)); } + first_pass = FALSE; + } while (devc->num_block_bytes != devc->memory_depth_digital); + + /* 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); } - /* 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++; + devc->num_block_bytes = 0; + g_array_free(tmp_samplebuf, TRUE); + g_array_free(buffdata, TRUE); } } - - /* 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); - } - 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 * 8; index++) { uint8_t value; if (low_channels) { value = g_array_index(data_low_channels, uint8_t, index); @@ -519,10 +617,12 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) switch (devc->model->series->protocol) { case NON_SPO_MODEL: case SPO_MODEL: - /* The older models need more time to prepare the the output buffers due to CPU speed. */ - wait = (devc->memory_depth_analog * 2.5); - sr_dbg("Waiting %.f0 ms for device to prepare the output buffers", wait / 1000); - g_usleep(wait); + if (strcmp(devc->model->series->name, "SDS2000X+")) { + /* The older models need more time to prepare the the output buffers due to CPU speed. */ + wait = (devc->memory_depth_analog * 2.5); + sr_dbg("Waiting %.f ms for device to prepare the output buffers", wait / 1000); + g_usleep(wait); + } if (sr_scpi_read_begin(scpi) != SR_OK) return TRUE; break; @@ -547,7 +647,6 @@ 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; devc->num_block_read = 0; if (len == -1) { @@ -566,13 +665,32 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) len = devc->num_samples; } else { sr_dbg("Requesting: %" PRIu64 " bytes.", devc->num_samples - devc->num_block_bytes); + /* SDS2000X+ sends 10MB or 5MB blocks, as found by "WAV:MAXPoint?". */ + /* It needs to have the next starting point specified to continue. */ + if (!strcmp(devc->model->series->name, "SDS2000X+")) { + 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:STARt %d", devc->num_block_bytes) != SR_OK) + return SR_ERR; + if (sr_scpi_send(sdi->conn, "WAV:DATA?") != SR_OK) + return SR_ERR; + sr_scpi_read_data(scpi, (char *)devc->buffer, 11); + } len = sr_scpi_read_data(scpi, (char *)devc->buffer, devc->num_samples-devc->num_block_bytes); - if (len == -1) { + 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; } + /* SDS2000X+: Throw away the last two 0A 0A bytes for full blocks. */ + if (!strcmp(devc->model->series->name, "SDS2000X+")) { + double full_block_size; + if (sr_scpi_get_double(sdi->conn, "WAV:MAXPoint?", &full_block_size) != SR_OK) + return SR_ERR; + if (len == full_block_size + 2) + len = full_block_size; + } devc->num_block_read++; devc->num_block_bytes += len; } @@ -589,7 +707,7 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) g_array_append_vals(data, devc->buffer, len); 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; + 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); } @@ -609,16 +727,18 @@ SR_PRIV int siglent_sds_receive(int fd, int revents, void *cb_data) g_array_free(data, TRUE); } len = 0; - if (devc->num_samples == (devc->num_block_bytes - SIGLENT_HEADER_SIZE)) { + if (devc->num_samples == devc->num_block_bytes) { 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 +861,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); @@ -888,9 +1008,42 @@ SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) switch (devc->model->series->protocol) { case SPO_MODEL: - case NON_SPO_MODEL: + case NON_SPO_MODEL: { + 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"); - res = sr_scpi_get_string(sdi->conn, cmd, &sample_points_string); + + /* 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 (!strcmp(devc->model->series->name, "SDS2000X+") && 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); samplerate_scope = 0; fvalue = 0; @@ -915,11 +1068,18 @@ 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); devc->memory_depth_analog = samplerate_scope; break; + } case ESERIES: cmd = g_strdup_printf("SANU? C1"); if (sr_scpi_get_float(sdi->conn, cmd, &fvalue) != SR_OK) @@ -935,10 +1095,6 @@ SR_PRIV int siglent_sds_get_dev_cfg_horizontal(const struct sr_dev_inst *sdi) break; }; - /* Get the timebase. */ - if (sr_scpi_get_float(sdi->conn, ":TDIV?", &devc->timebase) != SR_OK) - return SR_ERR; - sr_dbg("Current timebase: %g.", devc->timebase); devc->samplerate = devc->memory_depth_analog / (devc->timebase * devc->model->series->num_horizontal_divs); sr_dbg("Current samplerate: %0f.", devc->samplerate); diff --git a/src/hardware/siglent-sds/protocol.h b/src/hardware/siglent-sds/protocol.h index 89abaf640..ff35a1829 100644 --- a/src/hardware/siglent-sds/protocol.h +++ b/src/hardware/siglent-sds/protocol.h @@ -69,6 +69,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 +121,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];