diff --git a/hardware/rigol-ds/api.c b/hardware/rigol-ds/api.c index e0f4eaea..64f724bb 100644 --- a/hardware/rigol-ds/api.c +++ b/hardware/rigol-ds/api.c @@ -3,6 +3,7 @@ * * Copyright (C) 2012 Martin Ling * Copyright (C) 2013 Bert Vermeulen + * Copyright (C) 2013 Mathias Grimmberger * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,9 +28,6 @@ #include "libsigrok-internal.h" #include "protocol.h" -#define NUM_TIMEBASE 12 -#define NUM_VDIV 8 - static const int32_t hwopts[] = { SR_CONF_CONN, }; @@ -85,10 +83,17 @@ static const uint64_t timebases[][2] = { { 10, 1 }, { 20, 1 }, { 50, 1 }, + { 100, 1 }, + { 200, 1 }, + { 500, 1 }, + /* { 1000, 1 }, Confuses other code? */ }; static const uint64_t vdivs[][2] = { + /* microvolts */ + { 500, 1000000 }, /* millivolts */ + { 1, 1000 }, { 2, 1000 }, { 5, 1000 }, { 10, 1000 }, @@ -104,6 +109,9 @@ static const uint64_t vdivs[][2] = { { 10, 1 }, }; +#define NUM_TIMEBASE ARRAY_SIZE(timebases) +#define NUM_VDIV ARRAY_SIZE(vdivs) + static const char *trigger_sources[] = { "CH1", "CH2", @@ -133,13 +141,17 @@ static const char *coupling[] = { "GND", }; -static const char *supported_models[] = { - "DS1052E", - "DS1102E", - "DS1152E", - "DS1052D", - "DS1102D", - "DS1152D", +/* name, series, min timebase, max timebase, min vdiv, digital channels */ +static const struct rigol_ds_model supported_models[] = { + {"DS1052E", 1, {5, 1000000000}, {50, 1}, {2, 1000}, false}, + {"DS1102E", 1, {2, 1000000000}, {50, 1}, {2, 1000}, false}, + {"DS1152E", 1, {2, 1000000000}, {50, 1}, {2, 1000}, false}, + {"DS1052D", 1, {5, 1000000000}, {50, 1}, {2, 1000}, true}, + {"DS1102D", 1, {2, 1000000000}, {50, 1}, {2, 1000}, true}, + {"DS1152D", 1, {2, 1000000000}, {50, 1}, {2, 1000}, true}, + {"DS2072", 2, {5, 1000000000}, {500, 1}, {500, 1000000}, false}, + {"DS2102", 2, {5, 1000000000}, {500, 1}, {500, 1000000}, false}, + {"DS2202", 2, {2, 1000000000}, {500, 1}, {500, 1000000}, false}, }; SR_PRIV struct sr_dev_driver rigol_ds_driver_info; @@ -196,8 +208,8 @@ static int probe_port(const char *port, GSList **devices) struct sr_probe *probe; unsigned int i; int len, num_tokens; - gboolean matched, has_digital; - const char *manufacturer, *model, *version; + const char *manufacturer, *model_name, *version; + const struct rigol_ds_model *model = NULL; char buf[256]; gchar **tokens, *channel_name; @@ -229,25 +241,23 @@ static int probe_port(const char *port, GSList **devices) } manufacturer = tokens[0]; - model = tokens[1]; + model_name = tokens[1]; version = tokens[3]; - if (strcmp(manufacturer, "Rigol Technologies")) { + if (strcasecmp(manufacturer, "Rigol Technologies")) { g_strfreev(tokens); return SR_ERR_NA; } - matched = has_digital = FALSE; for (i = 0; i < ARRAY_SIZE(supported_models); i++) { - if (!strcmp(model, supported_models[i])) { - matched = TRUE; - has_digital = g_str_has_suffix(model, "D"); + if (!strcmp(model_name, supported_models[i].name)) { + model = &supported_models[i]; break; } } - if (!matched || !(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, - manufacturer, model, version))) { + if (!model || !(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, + manufacturer, model_name, version))) { g_strfreev(tokens); return SR_ERR_NA; } @@ -262,7 +272,7 @@ static int probe_port(const char *port, GSList **devices) if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) return SR_ERR_MALLOC; devc->limit_frames = 0; - devc->has_digital = has_digital; + devc->model = model; for (i = 0; i < 2; i++) { channel_name = (i == 0 ? "CH1" : "CH2"); @@ -275,7 +285,7 @@ static int probe_port(const char *port, GSList **devices) &devc->analog_groups[i]); } - if (devc->has_digital) { + if (devc->model->has_digital) { for (i = 0; i < 16; i++) { if (!(channel_name = g_strdup_printf("D%d", i))) return SR_ERR_MALLOC; @@ -291,6 +301,21 @@ static int probe_port(const char *port, GSList **devices) &devc->digital_group); } } + + for (i = 0; i < NUM_TIMEBASE; i++) { + if (!memcmp(&devc->model->min_timebase, &timebases[i], sizeof(uint64_t[2]))) + devc->timebases = &timebases[i]; + if (!memcmp(&devc->model->max_timebase, &timebases[i], sizeof(uint64_t[2]))) + devc->num_timebases = &timebases[i] - devc->timebases + 1; + } + + for (i = 0; i < NUM_VDIV; i++) { + if (!memcmp(&devc->model->min_vdiv, &vdivs[i], sizeof(uint64_t[2]))) { + devc->vdivs = &timebases[i]; + devc->num_vdivs = NUM_VDIV - (&timebases[i] - &timebases[0]); + } + } + sdi->priv = devc; *devices = g_slist_append(NULL, sdi); @@ -404,7 +429,7 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, switch (id) { case SR_CONF_NUM_TIMEBASE: - *data = g_variant_new_int32(NUM_TIMEBASE); + *data = g_variant_new_int32(devc->num_timebases); break; case SR_CONF_NUM_VDIV: if (!probe_group) { @@ -413,7 +438,7 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, } for (i = 0; i < 2; i++) { if (probe_group == &devc->analog_groups[i]) { - *data = g_variant_new_int32(NUM_VDIV); + *data = g_variant_new_int32(devc->num_vdivs); return SR_OK; } } @@ -470,19 +495,19 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, devc->horiz_triggerpos = t_dbl; /* We have the trigger offset as a percentage of the frame, but * need to express this in seconds. */ - t_dbl = -(devc->horiz_triggerpos - 0.5) * devc->timebase * NUM_TIMEBASE; + t_dbl = -(devc->horiz_triggerpos - 0.5) * devc->timebase * devc->num_timebases; ret = set_cfg(sdi, ":TIM:OFFS %.6f", t_dbl); break; case SR_CONF_TIMEBASE: g_variant_get(data, "(tt)", &p, &q); - for (i = 0; i < ARRAY_SIZE(timebases); i++) { - if (timebases[i][0] == p && timebases[i][1] == q) { + for (i = 0; i < devc->num_timebases; i++) { + if (devc->timebases[i][0] == p && devc->timebases[i][1] == q) { devc->timebase = (float)p / q; ret = set_cfg(sdi, ":TIM:SCAL %.9f", devc->timebase); break; } } - if (i == ARRAY_SIZE(timebases)) + if (i == devc->num_timebases) ret = SR_ERR_ARG; break; case SR_CONF_TRIGGER_SOURCE: @@ -559,7 +584,7 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, GVariant *tuple, *rational[2]; GVariantBuilder gvb; unsigned int i; - struct dev_context *devc; + struct dev_context *devc = sdi->priv; if (key == SR_CONF_SCAN_OPTIONS) { *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, @@ -619,9 +644,9 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, return SR_ERR_PROBE_GROUP; } g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); - for (i = 0; i < ARRAY_SIZE(vdivs); i++) { - rational[0] = g_variant_new_uint64(vdivs[i][0]); - rational[1] = g_variant_new_uint64(vdivs[i][1]); + for (i = 0; i < devc->num_vdivs; i++) { + rational[0] = g_variant_new_uint64(devc->vdivs[i][0]); + rational[1] = g_variant_new_uint64(devc->vdivs[i][1]); tuple = g_variant_new_tuple(rational, 2); g_variant_builder_add_value(&gvb, tuple); } @@ -629,9 +654,9 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, break; case SR_CONF_TIMEBASE: g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); - for (i = 0; i < ARRAY_SIZE(timebases); i++) { - rational[0] = g_variant_new_uint64(timebases[i][0]); - rational[1] = g_variant_new_uint64(timebases[i][1]); + for (i = 0; i < devc->num_timebases; i++) { + rational[0] = g_variant_new_uint64(devc->timebases[i][0]); + rational[1] = g_variant_new_uint64(devc->timebases[i][1]); tuple = g_variant_new_tuple(rational, 2); g_variant_builder_add_value(&gvb, tuple); } @@ -639,7 +664,7 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, break; case SR_CONF_TRIGGER_SOURCE: *data = g_variant_new_strv(trigger_sources, - devc->has_digital ? ARRAY_SIZE(trigger_sources) : 4); + devc->model->has_digital ? ARRAY_SIZE(trigger_sources) : 4); break; default: return SR_ERR_NA; @@ -697,19 +722,27 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); - /* Fetch the first frame. */ - if (devc->enabled_analog_probes) { - devc->channel_frame = devc->enabled_analog_probes->data; - if (rigol_ds_send(sdi, ":WAV:DATA? CHAN%d", - devc->channel_frame->index + 1) != SR_OK) - return SR_ERR; - } else { - devc->channel_frame = devc->enabled_digital_probes->data; - if (rigol_ds_send(sdi, ":WAV:DATA? DIG") != SR_OK) - return SR_ERR; - } + if (devc->model->series == 1) { + /* Fetch the first frame. */ + if (devc->enabled_analog_probes) { + devc->channel_frame = devc->enabled_analog_probes->data; + if (rigol_ds_send(sdi, ":WAV:DATA? CHAN%d", + devc->channel_frame->index + 1) != SR_OK) + return SR_ERR; + } else { + devc->channel_frame = devc->enabled_digital_probes->data; + if (rigol_ds_send(sdi, ":WAV:DATA? DIG") != SR_OK) + return SR_ERR; + } - devc->num_frame_bytes = 0; + devc->num_frame_bytes = 0; + } else { + if (devc->enabled_analog_probes) { + /* Assume there already was a trigger event - don't wait */ + if (rigol_ds2xx2_acquisition_start(sdi, FALSE) != SR_OK) + return SR_ERR; + } + } return SR_OK; } diff --git a/hardware/rigol-ds/protocol.c b/hardware/rigol-ds/protocol.c index 19e660d4..51cf25fa 100644 --- a/hardware/rigol-ds/protocol.c +++ b/hardware/rigol-ds/protocol.c @@ -3,6 +3,7 @@ * * Copyright (C) 2012 Martin Ling * Copyright (C) 2013 Bert Vermeulen + * Copyright (C) 2013 Mathias Grimmberger * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,11 +25,216 @@ #include #include #include +#include +#include #include #include "libsigrok.h" #include "libsigrok-internal.h" #include "protocol.h" +/* + * This is a unified protocol driver for the DS1000 and DS2000 series. + * + * DS1000 support tested with a Rigol DS1102D. + * + * DS2000 support tested with a Rigol DS2072 using firmware version 01.01.00.02. + * + * The Rigol DS2000 series scopes try to adhere to the IEEE 488.2 (I think) + * standard. If you want to read it - it costs real money... + * + * Every response from the scope has a linefeed appended because the + * standard says so. In principle this could be ignored because sending the + * next command clears the output queue of the scope. This driver tries to + * avoid doing that because it may cause an error being generated inside the + * scope and who knows what bugs the firmware has WRT this. + * + * Waveform data is transferred in a format called "arbitrary block program + * data" specified in IEEE 488.2. See Agilents programming manuals for their + * 2000/3000 series scopes for a nice description. + * + * Each data block from the scope has a header, e.g. "#900000001400". + * The '#' marks the start of a block. + * Next is one ASCII decimal digit between 1 and 9, this gives the number of + * ASCII decimal digits following. + * Last are the ASCII decimal digits giving the number of bytes (not + * samples!) in the block. + * + * After this header as many data bytes as indicated follow. + * + * Each data block has a trailing linefeed too. + */ + +static int get_cfg(const struct sr_dev_inst *sdi, char *cmd, char *reply, size_t maxlen); +static int get_cfg_int(const struct sr_dev_inst *sdi, char *cmd, int *i); + +static int parse_int(const char *str, int *ret) +{ + char *e; + long tmp; + + errno = 0; + tmp = strtol(str, &e, 10); + if (e == str || *e != '\0') { + sr_dbg("Failed to parse integer: '%s'", str); + return SR_ERR; + } + if (errno) { + sr_dbg("Failed to parse integer: '%s', numerical overflow", str); + return SR_ERR; + } + if (tmp > INT_MAX || tmp < INT_MIN) { + sr_dbg("Failed to parse integer: '%s', value to large/small", str); + return SR_ERR; + } + + *ret = (int)tmp; + return SR_OK; +} + +/* + * Waiting for a trigger event will return a timeout after 2, 3 seconds in + * order to not block the application. + */ + +static int rigol_ds2xx2_trigger_wait(const struct sr_dev_inst *sdi) +{ + char buf[20]; + struct dev_context *devc; + time_t start; + + if (!(devc = sdi->priv)) + return SR_ERR; + + start = time(NULL); + + /* + * Trigger status may return: + * "TD" - triggered + * "AUTO" - autotriggered + * "RUN" - running + * "WAIT" - waiting for trigger + * "STOP" - stopped + */ + + if (devc->trigger_wait_status == 1) { + do { + if (time(NULL) - start >= 3) { + sr_dbg("Timeout waiting for trigger"); + return SR_ERR_TIMEOUT; + } + + if (get_cfg(sdi, ":TRIG:STAT?", buf, sizeof(buf)) != SR_OK) + return SR_ERR; + } while (buf[0] == 'T' || buf[0] == 'A'); + + devc->trigger_wait_status = 2; + } + if (devc->trigger_wait_status == 2) { + do { + if (time(NULL) - start >= 3) { + sr_dbg("Timeout waiting for trigger"); + return SR_ERR_TIMEOUT; + } + + if (get_cfg(sdi, ":TRIG:STAT?", buf, sizeof(buf)) != SR_OK) + return SR_ERR; + } while (buf[0] != 'T' && buf[0] != 'A'); + + devc->trigger_wait_status = 0; + } + + return SR_OK; +} + +/* + * This needs to wait for a new trigger event to ensure that sample data is + * not returned twice. + * + * Unfortunately this will never really work because for sufficiently fast + * timebases it just can't catch the status changes. + * + * What would be needed is a trigger event register with autoreset like the + * Agilents have. The Rigols don't seem to have anything like this. + * + * The workaround is to only wait for the trigger when the timebase is slow + * enough. Of course this means that for faster timebases sample data can be + * returned multiple times. + */ + +SR_PRIV int rigol_ds2xx2_acquisition_start(const struct sr_dev_inst *sdi, + gboolean wait_for_trigger) +{ + struct dev_context *devc; + + if (!(devc = sdi->priv)) + return SR_ERR; + + devc->channel_frame = devc->enabled_analog_probes->data; + + sr_dbg("Starting acquisition on channel %d", + devc->channel_frame->index + 1); + + if (rigol_ds_send(sdi, ":WAV:FORM BYTE") != SR_OK) + return SR_ERR; + if (rigol_ds_send(sdi, ":WAV:SOUR CHAN%d", + devc->channel_frame->index + 1) != SR_OK) + return SR_ERR; + if (rigol_ds_send(sdi, ":WAV:MODE NORM") != SR_OK) + return SR_ERR; + + devc->num_frame_bytes = 0; + devc->num_block_bytes = 0; + + /* only wait for trigger if timbase 50 msecs/DIV or slower */ + if (wait_for_trigger && devc->timebase > 0.0499) + { + devc->trigger_wait_status = 1; + } else { + devc->trigger_wait_status = 0; + } + + return SR_OK; +} + +static int rigol_ds2xx2_read_header(struct sr_serial_dev_inst *serial) +{ + char start[3], length[10]; + int len, tmp; + + /* Read the hashsign and length digit. */ + tmp = serial_read(serial, start, 2); + start[2] = '\0'; + if (tmp != 2) + { + sr_err("Failed to read first two bytes of data block header."); + return -1; + } + if (start[0] != '#' || !isdigit(start[1]) || start[1] == '0') + { + sr_err("Received invalid data block header start '%s'.", start); + return -1; + } + len = atoi(start + 1); + + /* Read the data length. */ + tmp = serial_read(serial, length, len); + length[len] = '\0'; + if (tmp != len) + { + sr_err("Failed to read %d bytes of data block length.", len); + return -1; + } + if (parse_int(length, &len) != SR_OK) + { + sr_err("Received invalid data block length '%s'.", length); + return -1; + } + + sr_dbg("Received data block header: %s%s -> block length %d", start, length, len); + + return len; +} + SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; @@ -37,10 +243,10 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) struct sr_datafeed_packet packet; struct sr_datafeed_analog analog; struct sr_datafeed_logic logic; - unsigned char buf[DIGITAL_WAVEFORM_SIZE]; + unsigned char buf[DS2000_ANALOG_WAVEFORM_SIZE]; double vdiv, offset; - float data[ANALOG_WAVEFORM_SIZE]; - int len, i, waveform_size; + float data[DS2000_ANALOG_WAVEFORM_SIZE]; + int len, i, waveform_size, vref; struct sr_probe *probe; (void)fd; @@ -54,10 +260,42 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) serial = sdi->conn; if (revents == G_IO_IN) { + if (devc->trigger_wait_status > 0) { + if (rigol_ds2xx2_trigger_wait(sdi) != SR_OK) + return TRUE; + } + + if (devc->model->series == 2 && devc->num_block_bytes == 0) { + sr_dbg("New block header expected"); + if (rigol_ds_send(sdi, ":WAV:DATA?") != SR_OK) + return TRUE; + len = rigol_ds2xx2_read_header(serial); + if (len == -1) + return TRUE; + /* At slow timebases the scope sometimes returns + * "short" data blocks, with apparently no way to + * get the rest of the data. Discard these, the + * complete data block will appear eventually. + */ + if (len < DS2000_ANALOG_WAVEFORM_SIZE) { + sr_dbg("Discarding short data block"); + serial_read(serial, buf, len + 1); + return TRUE; + } + devc->num_block_bytes = len; + devc->num_block_read = 0; + } + probe = devc->channel_frame; - waveform_size = probe->type == SR_PROBE_ANALOG ? - ANALOG_WAVEFORM_SIZE : DIGITAL_WAVEFORM_SIZE; - len = serial_read(serial, buf, waveform_size - devc->num_frame_bytes); + if (devc->model->series == 2) { + len = devc->num_block_bytes - devc->num_block_read; + len = serial_read(serial, buf, + len < DS2000_ANALOG_WAVEFORM_SIZE ? len : DS2000_ANALOG_WAVEFORM_SIZE); + } else { + waveform_size = probe->type == SR_PROBE_ANALOG ? + DS1000_ANALOG_WAVEFORM_SIZE : DIGITAL_WAVEFORM_SIZE; + len = serial_read(serial, buf, waveform_size - devc->num_frame_bytes); + } sr_dbg("Received %d bytes.", len); if (len == -1) return TRUE; @@ -69,11 +307,17 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) } if (probe->type == SR_PROBE_ANALOG) { - for (i = 0; i < len; i++) { - vdiv = devc->vdiv[probe->index]; - offset = devc->vert_offset[probe->index]; - data[i] = vdiv / 25.6 * (128 - buf[i]) - offset; - } + if (devc->model->series == 2) + devc->num_block_read += len; + vref = devc->vert_reference[probe->index]; + vdiv = devc->vdiv[probe->index] / 25.6; + offset = devc->vert_offset[probe->index]; + if (devc->model->series == 2) + for (i = 0; i < len; i++) + data[i] = ((int)buf[i] - vref) * vdiv - offset; + else + for (i = 0; i < len; i++) + data[i] = (128 - buf[i]) * vdiv - offset; analog.probes = g_slist_append(NULL, probe); analog.num_samples = len; analog.data = data; @@ -85,9 +329,19 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) sr_session_send(cb_data, &packet); g_slist_free(analog.probes); - if (len != ANALOG_WAVEFORM_SIZE) - /* Don't have the whole frame yet. */ - return TRUE; + if (devc->model->series == 2) { + devc->num_frame_bytes += len; + + if (devc->num_frame_bytes < DS2000_ANALOG_WAVEFORM_SIZE) + /* Don't have the whole frame yet. */ + return TRUE; + + sr_dbg("Frame completed, %d samples", devc->num_frame_bytes); + } else { + if (len != DS1000_ANALOG_WAVEFORM_SIZE) + /* Don't have the whole frame yet. */ + return TRUE; + } } else { logic.length = len - 10; logic.unitsize = 2; @@ -104,16 +358,22 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) /* End of the frame. */ packet.type = SR_DF_FRAME_END; sr_session_send(sdi, &packet); - devc->num_frame_bytes = 0; + if (devc->model->series == 1) + devc->num_frame_bytes = 0; if (devc->enabled_analog_probes && devc->channel_frame == devc->enabled_analog_probes->data && devc->enabled_analog_probes->next != NULL) { /* We got the frame for the first analog channel, but * there's a second analog channel. */ - devc->channel_frame = devc->enabled_analog_probes->next->data; - rigol_ds_send(sdi, ":WAV:DATA? CHAN%c", - devc->channel_frame->name[2]); + if (devc->model->series == 2) { + /* Do not wait for trigger to try and keep channel data related. */ + rigol_ds2xx2_acquisition_start(sdi, FALSE); + } else { + devc->channel_frame = devc->enabled_analog_probes->next->data; + rigol_ds_send(sdi, ":WAV:DATA? CHAN%c", + devc->channel_frame->name[2]); + } } else { /* Done with both analog channels in this frame. */ if (devc->enabled_digital_probes @@ -128,13 +388,22 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) sdi->driver->dev_acquisition_stop(sdi, cb_data); } else { /* Get the next frame, starting with the first analog channel. */ - if (devc->enabled_analog_probes) { - devc->channel_frame = devc->enabled_analog_probes->data; - rigol_ds_send(sdi, ":WAV:DATA? CHAN%c", - devc->channel_frame->name[2]); + if (devc->model->series == 2) { + if (devc->enabled_analog_probes) { + /* Must wait for trigger because at + * slow timebases the scope will + * return old data otherwise. */ + rigol_ds2xx2_acquisition_start(sdi, TRUE); + } } else { - devc->channel_frame = devc->enabled_digital_probes->data; - rigol_ds_send(sdi, ":WAV:DATA? DIG"); + if (devc->enabled_analog_probes) { + devc->channel_frame = devc->enabled_analog_probes->data; + rigol_ds_send(sdi, ":WAV:DATA? CHAN%c", + devc->channel_frame->name[2]); + } else { + devc->channel_frame = devc->enabled_digital_probes->data; + rigol_ds_send(sdi, ":WAV:DATA? DIG"); + } } } } @@ -167,26 +436,47 @@ SR_PRIV int rigol_ds_send(const struct sr_dev_inst *sdi, const char *format, ... return ret; } -static int get_cfg(const struct sr_dev_inst *sdi, char *cmd, char *reply) +static int get_cfg(const struct sr_dev_inst *sdi, char *cmd, char *reply, size_t maxlen) { int len; + struct dev_context *devc = sdi->priv; if (rigol_ds_send(sdi, cmd) != SR_OK) return SR_ERR; - if ((len = serial_read(sdi->conn, reply, 255)) < 0) + if ((len = serial_read(sdi->conn, reply, maxlen - 1)) < 0) return SR_ERR; reply[len] = '\0'; + + if (devc->model->series == 2) { + /* get rid of trailing linefeed */ + if (len >= 1 && reply[len-1] == '\n') + reply[len-1] = '\0'; + } + sr_spew("Received '%s'.", reply); return SR_OK; } +static int get_cfg_int(const struct sr_dev_inst *sdi, char *cmd, int *i) +{ + char buf[32]; + + if (get_cfg(sdi, cmd, buf, sizeof(buf)) != SR_OK) + return SR_ERR; + + if (parse_int(buf, i) != SR_OK) + return SR_ERR; + + return SR_OK; +} + static int get_cfg_float(const struct sr_dev_inst *sdi, char *cmd, float *f) { - char buf[256], *e; + char buf[32], *e; - if (get_cfg(sdi, cmd, buf) != SR_OK) + if (get_cfg(sdi, cmd, buf, sizeof(buf)) != SR_OK) return SR_ERR; *f = strtof(buf, &e); if (e == buf || (fpclassify(*f) & (FP_ZERO | FP_NORMAL)) == 0) { @@ -199,11 +489,10 @@ static int get_cfg_float(const struct sr_dev_inst *sdi, char *cmd, float *f) static int get_cfg_string(const struct sr_dev_inst *sdi, char *cmd, char **buf) { - if (!(*buf = g_try_malloc0(256))) return SR_ERR_MALLOC; - if (get_cfg(sdi, cmd, *buf) != SR_OK) + if (get_cfg(sdi, cmd, *buf, 256) != SR_OK) return SR_ERR; return SR_OK; @@ -220,18 +509,18 @@ SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi) /* Analog channel state. */ if (get_cfg_string(sdi, ":CHAN1:DISP?", &t_s) != SR_OK) return SR_ERR; - devc->analog_channels[0] = !strcmp(t_s, "ON") ? TRUE : FALSE; + devc->analog_channels[0] = !strcmp(t_s, "ON") || !strcmp(t_s, "1"); g_free(t_s); if (get_cfg_string(sdi, ":CHAN2:DISP?", &t_s) != SR_OK) return SR_ERR; - devc->analog_channels[1] = !strcmp(t_s, "ON") ? TRUE : FALSE; + devc->analog_channels[1] = !strcmp(t_s, "ON") || !strcmp(t_s, "1"); g_free(t_s); sr_dbg("Current analog channel state CH1 %s CH2 %s", devc->analog_channels[0] ? "on" : "off", devc->analog_channels[1] ? "on" : "off"); /* Digital channel state. */ - if (devc->has_digital) { + if (devc->model->has_digital) { sr_dbg("Current digital channel state:"); for (i = 0; i < 16; i++) { cmd = g_strdup_printf(":DIG%d:TURN?", i); @@ -248,21 +537,35 @@ SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi) /* Timebase. */ if (get_cfg_float(sdi, ":TIM:SCAL?", &devc->timebase) != SR_OK) return SR_ERR; - sr_dbg("Current timebase %f", devc->timebase); + sr_dbg("Current timebase %g", devc->timebase); /* Vertical gain. */ if (get_cfg_float(sdi, ":CHAN1:SCAL?", &devc->vdiv[0]) != SR_OK) return SR_ERR; if (get_cfg_float(sdi, ":CHAN2:SCAL?", &devc->vdiv[1]) != SR_OK) return SR_ERR; - sr_dbg("Current vertical gain CH1 %f CH2 %f", devc->vdiv[0], devc->vdiv[1]); + sr_dbg("Current vertical gain CH1 %g CH2 %g", devc->vdiv[0], devc->vdiv[1]); + + if (devc->model->series == 2) { + /* Vertical reference - not certain if this is the place to read it. */ + if (rigol_ds_send(sdi, ":WAV:SOUR CHAN1") != SR_OK) + return SR_ERR; + if (get_cfg_int(sdi, ":WAV:YREF?", &devc->vert_reference[0]) != SR_OK) + return SR_ERR; + if (rigol_ds_send(sdi, ":WAV:SOUR CHAN2") != SR_OK) + return SR_ERR; + if (get_cfg_int(sdi, ":WAV:YREF?", &devc->vert_reference[1]) != SR_OK) + return SR_ERR; + sr_dbg("Current vertical reference CH1 %d CH2 %d", + devc->vert_reference[0], devc->vert_reference[1]); + } /* Vertical offset. */ if (get_cfg_float(sdi, ":CHAN1:OFFS?", &devc->vert_offset[0]) != SR_OK) return SR_ERR; if (get_cfg_float(sdi, ":CHAN2:OFFS?", &devc->vert_offset[1]) != SR_OK) return SR_ERR; - sr_dbg("Current vertical offset CH1 %f CH2 %f", devc->vert_offset[0], + sr_dbg("Current vertical offset CH1 %g CH2 %g", devc->vert_offset[0], devc->vert_offset[1]); /* Coupling. */ @@ -281,7 +584,7 @@ SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi) /* Horizontal trigger position. */ if (get_cfg_float(sdi, ":TIM:OFFS?", &devc->horiz_triggerpos) != SR_OK) return SR_ERR; - sr_dbg("Current horizontal trigger position %f", devc->horiz_triggerpos); + sr_dbg("Current horizontal trigger position %g", devc->horiz_triggerpos); /* Trigger slope. */ if (get_cfg_string(sdi, ":TRIG:EDGE:SLOP?", &devc->trigger_slope) != SR_OK) diff --git a/hardware/rigol-ds/protocol.h b/hardware/rigol-ds/protocol.h index cce22b28..cd49df5d 100644 --- a/hardware/rigol-ds/protocol.h +++ b/hardware/rigol-ds/protocol.h @@ -22,6 +22,7 @@ #define LIBSIGROK_HARDWARE_RIGOL_DS_PROTOCOL_H #include +#include #include "libsigrok.h" #include "libsigrok-internal.h" @@ -34,13 +35,29 @@ #define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) #define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) -#define ANALOG_WAVEFORM_SIZE 600 +#define DS1000_ANALOG_WAVEFORM_SIZE 600 +#define DS2000_ANALOG_WAVEFORM_SIZE 1400 #define DIGITAL_WAVEFORM_SIZE 1210 +struct rigol_ds_model { + char *name; + unsigned int series; + uint64_t min_timebase[2]; + uint64_t max_timebase[2]; + uint64_t min_vdiv[2]; + bool has_digital; +}; + /** Private, per-device-instance driver context. */ struct dev_context { - /* Device features */ - gboolean has_digital; + /* Device model */ + const struct rigol_ds_model *model; + + /* Device properties */ + const uint64_t (*timebases)[2]; + uint64_t num_timebases; + const uint64_t (*vdivs)[2]; + uint64_t num_vdivs; /* Probe groups */ struct sr_probe_group analog_groups[2]; @@ -57,6 +74,7 @@ struct dev_context { gboolean digital_channels[16]; float timebase; float vdiv[2]; + int vert_reference[2]; float vert_offset[2]; char *trigger_source; float horiz_triggerpos; @@ -65,10 +83,18 @@ struct dev_context { /* Operational state */ uint64_t num_frames; + /* FIXME: misnomer, actually this is number of frame samples? */ uint64_t num_frame_bytes; struct sr_probe *channel_frame; + /* Number of bytes in current data block, if 0 block header expected */ + uint64_t num_block_bytes; + /* Number of data block bytes already read */ + uint64_t num_block_read; + /* Trigger waiting status, 0 - don't wait */ + int trigger_wait_status; }; +SR_PRIV int rigol_ds2xx2_acquisition_start(const struct sr_dev_inst *sdi, gboolean wait_for_trigger); SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data); SR_PRIV int rigol_ds_send(const struct sr_dev_inst *sdi, const char *format, ...); SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi);