From ac86ac6928242796952b8f147f1d2ba1640167dd Mon Sep 17 00:00:00 2001 From: Frederic Borry Date: Mon, 22 Jul 2024 12:14:32 +0200 Subject: [PATCH] Added support for DHO 800/900 models Based on the work of Diana Ellefson (OrionOth) : https://github.com/sigrokproject/libsigrok/pull/229 and RemiNV : https://github.com/sigrokproject/libsigrok/commit/3430e8ececf579205c782eb173b3cf425712b858 --- contrib/60-libsigrok.rules | 6 ++ src/hardware/rigol-ds/api.c | 112 ++++++++++++++++++++++++++----- src/hardware/rigol-ds/protocol.c | 77 ++++++++++++++++----- src/hardware/rigol-ds/protocol.h | 1 + 4 files changed, 163 insertions(+), 33 deletions(-) diff --git a/contrib/60-libsigrok.rules b/contrib/60-libsigrok.rules index b6ac3ba04..29e545d42 100644 --- a/contrib/60-libsigrok.rules +++ b/contrib/60-libsigrok.rules @@ -249,6 +249,12 @@ ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0e11", ENV{ID_SIGROK}="1" # Rigol MSO5000 series ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0515", ENV{ID_SIGROK}="1" +# Rigol DHO800 series +ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="044d", ENV{ID_SIGROK}="1" + +# Rigol DHO800 and DHO900 series +ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="044c", ENV{ID_SIGROK}="1" + # Rohde&Schwarz HMO series mixed-signal oscilloscope (previously branded Hameg) VCP/USBTMC mode ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0117", ENV{ID_SIGROK}="1" ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0118", ENV{ID_SIGROK}="1" diff --git a/src/hardware/rigol-ds/api.c b/src/hardware/rigol-ds/api.c index 6703d1cea..b1f6e1570 100644 --- a/src/hardware/rigol-ds/api.c +++ b/src/hardware/rigol-ds/api.c @@ -105,6 +105,7 @@ static const uint64_t timebases[][2] = { static const uint64_t vdivs[][2] = { /* microvolts */ + { 200, 1000000 }, { 500, 1000000 }, /* millivolts */ { 1, 1000 }, @@ -185,6 +186,8 @@ enum series { DS4000, MSO5000, MSO7000A, + DHO800, + DHO900, }; /* short name, full name */ @@ -217,6 +220,10 @@ static const struct rigol_ds_series supported_series[] = { {1000, 1}, {500, 1000000}, 10, 1000, 0}, [MSO7000A] = {VENDOR(AGILENT), "MSO7000A", PROTOCOL_V4, FORMAT_IEEE488_2, {50, 1}, {2, 1000}, 10, 1000, 8000000}, + [DHO800] = {VENDOR(RIGOL), "DHO800", PROTOCOL_V6, FORMAT_IEEE488_2, + {500, 1}, {500, 1000000}, 10, 1000, 0}, + [DHO900] = {VENDOR(RIGOL), "DHO900", PROTOCOL_V6, FORMAT_IEEE488_2, + {500, 1}, {200, 1000000}, 10, 1000, 0}, }; #define SERIES(x) &supported_series[x] @@ -291,6 +298,14 @@ static const struct rigol_ds_model supported_models[] = { {SERIES(MSO5000), "MSO5354", {1, 1000000000}, CH_INFO(4, true), std_cmd}, /* TODO: Digital channels are not yet supported on MSO7000A. */ {SERIES(MSO7000A), "MSO7034A", {2, 1000000000}, CH_INFO(4, false), mso7000a_cmd}, + {SERIES(DHO800), "DHO802", {5, 1000000000}, CH_INFO(2, false), std_cmd}, + {SERIES(DHO800), "DHO804", {5, 1000000000}, CH_INFO(4, false), std_cmd}, + {SERIES(DHO800), "DHO812", {5, 1000000000}, CH_INFO(2, false), std_cmd}, + {SERIES(DHO800), "DHO814", {5, 1000000000}, CH_INFO(4, false), std_cmd}, + {SERIES(DHO900), "DHO914", {2, 1000000000}, CH_INFO(4, true), std_cmd}, + {SERIES(DHO900), "DHO914S", {2, 1000000000}, CH_INFO(4, true), std_cmd}, + {SERIES(DHO900), "DHO924", {2, 1000000000}, CH_INFO(4, true), std_cmd}, + {SERIES(DHO900), "DHO924S", {2, 1000000000}, CH_INFO(4, true), std_cmd}, }; static struct sr_dev_driver rigol_ds_driver_info; @@ -913,20 +928,45 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) some_digital = TRUE; /* Turn on LA module if currently off. */ if (!devc->la_enabled) { - if (rigol_ds_config_set(sdi, protocol >= PROTOCOL_V3 ? - ":LA:STAT ON" : ":LA:DISP ON") != SR_OK) + switch (protocol) { + case PROTOCOL_V1: + case PROTOCOL_V2: + cmd = ":LA:DISP ON"; + break; + case PROTOCOL_V3: + case PROTOCOL_V4: + case PROTOCOL_V5: + cmd = ":LA:STAT ON"; + break; + case PROTOCOL_V6: + default: + cmd = ":LA:ENAB ON"; + break; + } + if (rigol_ds_config_set(sdi, cmd) != SR_OK) return SR_ERR; devc->la_enabled = TRUE; } } if (ch->enabled != devc->digital_channels[ch->index]) { /* Enabled channel is currently disabled, or vice versa. */ - if (protocol >= PROTOCOL_V5) - cmd = ":LA:DISP D%d,%s"; - else if (protocol >= PROTOCOL_V3) - cmd = ":LA:DIG%d:DISP %s"; - else - cmd = ":DIG%d:TURN %s"; + switch (protocol) { + case PROTOCOL_V1: + case PROTOCOL_V2: + cmd = ":DIG%d:TURN %s"; + break; + case PROTOCOL_V3: + case PROTOCOL_V4: + cmd = ":LA:DIG%d:DISP %s"; + break; + case PROTOCOL_V5: + cmd = ":LA:DISP D%d,%s"; + break; + case PROTOCOL_V6: + default: + cmd = ":LA:DIG:ENAB D%d,%s"; + break; + } if (rigol_ds_config_set(sdi, cmd, ch->index, ch->enabled ? "ON" : "OFF") != SR_OK) @@ -940,10 +980,29 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) return SR_ERR; /* Turn off LA module if on and no digital channels selected. */ - if (devc->la_enabled && !some_digital) - if (rigol_ds_config_set(sdi, - devc->model->series->protocol >= PROTOCOL_V3 ? - ":LA:STAT OFF" : ":LA:DISP OFF") != SR_OK) + if (devc->la_enabled && !some_digital) { + switch (protocol) { + case PROTOCOL_V1: + case PROTOCOL_V2: + cmd = ":LA:DISP OFF"; + break; + case PROTOCOL_V3: + case PROTOCOL_V4: + case PROTOCOL_V5: + cmd = ":LA:STAT OFF"; + break; + case PROTOCOL_V6: + default: + cmd = ":LA:ENAB OFF"; + break; + } + if (rigol_ds_config_set(sdi, cmd) != SR_OK) + return SR_ERR; + } + + /* For DHO scopes, trigger must be in stop mode to start memory or segmented acquisition */ + if((protocol == PROTOCOL_V6)&&((devc->data_source == DATA_SOURCE_SEGMENTED)||(devc->data_source == DATA_SOURCE_MEMORY))) + if (rigol_ds_config_set(sdi, ":STOP") != SR_OK) return SR_ERR; /* Set memory mode. */ @@ -969,10 +1028,28 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) devc->num_frames_segmented = frames; break; } + case PROTOCOL_V6: + /* DHO scopes need to be in UltraAcquire mode for segmented acquisoton */ + /* This command is not working as for firmware version v00.01.02.00.02 of 2023/12/28 + the scope has to be put manually in UltraAcquire mode for segmented acquisition to work */ + //if (rigol_ds_config_set(sdi, ":ACQ:TYPE ULTR") != SR_OK) + // return SR_ERR; */ + + int frames = 0; + //if (sr_scpi_get_int(sdi->conn, ":REC:FRAM?", &frames) != SR_OK) + if (sr_scpi_get_int(sdi->conn, ":ACQ:ULTR:MAXF?", &frames) != SR_OK) + return SR_ERR; + if (frames <= 0) { + sr_err("No segmented data available"); + return SR_ERR; + } + devc->num_frames_segmented = frames; + /* Continue with REC:CURR command */ + // fall through case PROTOCOL_V5: /* The frame limit has to be read on the fly, just set up * reading of the first frame */ - if (rigol_ds_config_set(sdi, "REC:CURR 1") != SR_OK) + if (rigol_ds_config_set(sdi, ":REC:CURR 1") != SR_OK) return SR_ERR; break; default: @@ -984,7 +1061,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) devc->analog_frame_size = analog_frame_size(sdi); devc->digital_frame_size = digital_frame_size(sdi); - switch (devc->model->series->protocol) { + switch (protocol) { case PROTOCOL_V2: if (rigol_ds_config_set(sdi, ":ACQ:MEMD LONG") != SR_OK) return SR_ERR; @@ -1021,7 +1098,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) (devc->timebase * devc->model->series->num_horizontal_divs); } else { float xinc; - if (devc->model->series->protocol < PROTOCOL_V3) { + if (protocol < PROTOCOL_V3) { sr_err("Cannot get samplerate (below V3)."); return SR_ERR; } @@ -1037,8 +1114,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) devc->sample_rate = 1. / xinc; } - if (rigol_ds_capture_start(sdi) != SR_OK) - return SR_ERR; + ret = rigol_ds_capture_start(sdi); + if (ret != SR_OK) + return ret; /* Start of first frame. */ std_session_send_df_frame_begin(sdi); diff --git a/src/hardware/rigol-ds/protocol.c b/src/hardware/rigol-ds/protocol.c index 05aaf113f..f82ec4140 100644 --- a/src/hardware/rigol-ds/protocol.c +++ b/src/hardware/rigol-ds/protocol.c @@ -324,10 +324,13 @@ SR_PRIV int rigol_ds_config_set(const struct sr_dev_inst *sdi, const char *forma return SR_ERR; if (devc->model->series->protocol == PROTOCOL_V2) { - /* The DS1000 series needs this stupid delay, *OPC? doesn't work. */ + /* The DS1000 series needs this stupid delay, *OPC? doesn't work.*/ sr_spew("delay %dms", 100); g_usleep(100 * 1000); return SR_OK; + } else if (devc->model->series->protocol == PROTOCOL_V6) { + /* Same goes for DHO series but they can handle faster response...*/ + return SR_OK; } else { return sr_scpi_get_opc(sdi->conn); } @@ -385,6 +388,7 @@ SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi) case PROTOCOL_V3: case PROTOCOL_V4: case PROTOCOL_V5: + case PROTOCOL_V6: if (first_frame && rigol_ds_config_set(sdi, ":WAV:FORM BYTE") != SR_OK) return SR_ERR; if (devc->data_source == DATA_SOURCE_LIVE) { @@ -417,13 +421,23 @@ SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi) buffer_samples = devc->model->series->buffer_samples; if (first_frame && buffer_samples == 0) { - /* The DS4000 series does not have a fixed memory depth, it + /* The DS4000 and DHO series does not have a fixed memory depth, it * can be chosen from the menu and also varies with number * of active channels. Retrieve the actual number with the * ACQ:MDEP command. */ sr_scpi_get_int(sdi->conn, "ACQ:MDEP?", &buffer_samples); + /* TODO : what about digital channels ? */ devc->analog_frame_size = devc->digital_frame_size = buffer_samples; + + /* For some reason, as for DHO firmware version v00.01.02.00.02 of 2023/12/28, + * segmented acquisition does not work over multiple data blocks : DATA? command on a frame + * portion results in a header, declaring an empty content, of the form '#9000000000'. */ + if(devc->data_source == DATA_SOURCE_SEGMENTED && devc->analog_frame_size > ACQ_BLOCK_SIZE) { + sr_err("Data source 'Segmented' not supported for memory depth > %d points.",ACQ_BLOCK_SIZE); + return SR_ERR_NA; + } + } else if (first_frame) { @@ -499,6 +513,7 @@ SR_PRIV int rigol_ds_channel_start(const struct sr_dev_inst *sdi) break; case PROTOCOL_V4: case PROTOCOL_V5: + case PROTOCOL_V6: if (ch->type == SR_CHANNEL_ANALOG) { if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d", ch->index + 1) != SR_OK) @@ -514,7 +529,7 @@ SR_PRIV int rigol_ds_channel_start(const struct sr_dev_inst *sdi) ":WAV:MODE NORM" :":WAV:MODE RAW") != SR_OK) return SR_ERR; - if (devc->data_source != DATA_SOURCE_LIVE) { + if ((devc->data_source != DATA_SOURCE_LIVE) && (devc->model->series->protocol != PROTOCOL_V6)) { if (rigol_ds_config_set(sdi, ":WAV:RES") != SR_OK) return SR_ERR; } @@ -669,17 +684,17 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) if (devc->num_block_bytes == 0) { if (devc->model->series->protocol >= PROTOCOL_V4) { - if (first_frame && rigol_ds_config_set(sdi, ":WAV:START %d", + if ((first_frame || (devc->model->series->protocol == PROTOCOL_V6)) && rigol_ds_config_set(sdi, ":WAV:START %d", devc->num_channel_bytes + 1) != SR_OK) return TRUE; - if (first_frame && rigol_ds_config_set(sdi, ":WAV:STOP %d", + if ((first_frame || (devc->model->series->protocol == PROTOCOL_V6)) && rigol_ds_config_set(sdi, ":WAV:STOP %d", MIN(devc->num_channel_bytes + ACQ_BLOCK_SIZE, devc->analog_frame_size)) != SR_OK) return TRUE; } if (devc->model->series->protocol >= PROTOCOL_V3) { - if (rigol_ds_config_set(sdi, ":WAV:BEG") != SR_OK) + if ((devc->model->series->protocol != PROTOCOL_V6) && rigol_ds_config_set(sdi, ":WAV:BEG") != SR_OK) return TRUE; if (sr_scpi_send(sdi->conn, ":WAV:DATA?") != SR_OK) return TRUE; @@ -846,6 +861,13 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) /* Get the next frame, starting with the first channel. */ devc->channel_entry = devc->enabled_channels; + if (devc->data_source == DATA_SOURCE_SEGMENTED && + devc->model->series->protocol == PROTOCOL_V6) { + /* Move to next frame in segmented mode*/ + if (rigol_ds_config_set(sdi, ":REC:CURR %d", devc->num_frames + 1) != SR_OK) + return SR_ERR; + } + rigol_ds_capture_start(sdi); /* Start of next frame. */ @@ -882,20 +904,43 @@ SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi) /* Digital channel state. */ if (devc->model->has_digital) { - if (sr_scpi_get_bool(sdi->conn, - devc->model->series->protocol >= PROTOCOL_V3 ? - ":LA:STAT?" : ":LA:DISP?", - &devc->la_enabled) != SR_OK) + switch (devc->model->series->protocol) { + case PROTOCOL_V1: + case PROTOCOL_V2: + cmd = ":LA:DISP?"; + break; + case PROTOCOL_V3: + case PROTOCOL_V4: + case PROTOCOL_V5: + cmd = ":LA:STAT?"; + break; + case PROTOCOL_V6: + default: + cmd = ":LA:ENAB?"; + break; + } + if (sr_scpi_get_bool(sdi->conn, cmd, &devc->la_enabled) != SR_OK) return SR_ERR; sr_dbg("Logic analyzer %s, current digital channel state:", devc->la_enabled ? "enabled" : "disabled"); for (i = 0; i < ARRAY_SIZE(devc->digital_channels); i++) { - if (devc->model->series->protocol >= PROTOCOL_V5) - cmd = g_strdup_printf(":LA:DISP? D%d", i); - else if (devc->model->series->protocol >= PROTOCOL_V3) - cmd = g_strdup_printf(":LA:DIG%d:DISP?", i); - else - cmd = g_strdup_printf(":DIG%d:TURN?", i); + switch (devc->model->series->protocol) { + case PROTOCOL_V1: + case PROTOCOL_V2: + cmd = g_strdup_printf(":DIG%d:TURN?", i); + break; + case PROTOCOL_V3: + case PROTOCOL_V4: + cmd = g_strdup_printf(":LA:DIG%d:DISP?", i); + break; + case PROTOCOL_V5: + cmd = g_strdup_printf(":LA:DISP? D%d", i); + break; + case PROTOCOL_V6: + default: + cmd = g_strdup_printf(":LA:DIG:ENAB? D%d", i); + break; + } res = sr_scpi_get_bool(sdi->conn, cmd, &devc->digital_channels[i]); g_free(cmd); if (res != SR_OK) diff --git a/src/hardware/rigol-ds/protocol.h b/src/hardware/rigol-ds/protocol.h index e2efffa22..dbfbf1464 100644 --- a/src/hardware/rigol-ds/protocol.h +++ b/src/hardware/rigol-ds/protocol.h @@ -43,6 +43,7 @@ enum protocol_version { PROTOCOL_V3, /* DS2000, DSO1000 */ PROTOCOL_V4, /* DS1000Z */ PROTOCOL_V5, /* MSO5000 */ + PROTOCOL_V6, /* DHO800, DHO900 */ }; enum data_format {