Skip to content

Commit

Permalink
Added support for DHO 800/900 models
Browse files Browse the repository at this point in the history
Based on the work of Diana Ellefson (OrionOth) : sigrokproject#229
and RemiNV : sigrokproject@3430e8e
  • Loading branch information
Frederic Borry committed Jul 22, 2024
1 parent f91fb2a commit ac86ac6
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 33 deletions.
6 changes: 6 additions & 0 deletions contrib/60-libsigrok.rules
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
112 changes: 95 additions & 17 deletions src/hardware/rigol-ds/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ static const uint64_t timebases[][2] = {

static const uint64_t vdivs[][2] = {
/* microvolts */
{ 200, 1000000 },
{ 500, 1000000 },
/* millivolts */
{ 1, 1000 },
Expand Down Expand Up @@ -185,6 +186,8 @@ enum series {
DS4000,
MSO5000,
MSO7000A,
DHO800,
DHO900,
};

/* short name, full name */
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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. */
Expand All @@ -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:
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down
77 changes: 61 additions & 16 deletions src/hardware/rigol-ds/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/hardware/rigol-ds/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ enum protocol_version {
PROTOCOL_V3, /* DS2000, DSO1000 */
PROTOCOL_V4, /* DS1000Z */
PROTOCOL_V5, /* MSO5000 */
PROTOCOL_V6, /* DHO800, DHO900 */
};

enum data_format {
Expand Down

0 comments on commit ac86ac6

Please sign in to comment.