]> sigrok.org Git - libsigrok.git/blobdiff - hardware/rigol-ds1xx2/protocol.c
rigol-ds1xx2: Support for all channels, proper defaults
[libsigrok.git] / hardware / rigol-ds1xx2 / protocol.c
index 19e402c386c4b60aff34c957061b1fd862107ad7..fcac2cf59c59efcc642c9111cebe52e7d956cd8a 100644 (file)
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
+#include <math.h>
 #include <glib.h>
 #include "libsigrok.h"
 #include "libsigrok-internal.h"
 #include "protocol.h"
 
-SR_PRIV int rigol_ds1xx2_receive_data(int fd, int revents, void *cb_data)
+SR_PRIV int rigol_ds1xx2_receive(int fd, int revents, void *cb_data)
 {
        struct sr_dev_inst *sdi;
        struct dev_context *devc;
        struct sr_datafeed_packet packet;
        struct sr_datafeed_analog analog;
        unsigned char buf[WAVEFORM_SIZE];
+       double vdiv, offset;
        float data[WAVEFORM_SIZE];
-       int len, i;
+       int probenum, len, i;
 
        if (!(sdi = cb_data))
                return TRUE;
@@ -56,9 +58,13 @@ SR_PRIV int rigol_ds1xx2_receive_data(int fd, int revents, void *cb_data)
                        sr_session_send(sdi, &packet);
                }
 
-               for (i = 0; i < len; i++)
-                       data[i] = devc->scale / 25.6 * (128 - buf[i]) - devc->offset;
-               analog.probes = devc->enabled_probes;
+               probenum = devc->channel_frame->name[2] == '1' ? 0 : 1;
+               for (i = 0; i < len; i++) {
+                       vdiv = devc->vdiv[probenum];
+                       offset = devc->vert_offset[probenum];
+                       data[i] = vdiv / 25.6 * (128 - buf[i]) - offset;
+               }
+               analog.probes = g_slist_append(NULL, devc->channel_frame);
                analog.num_samples = len;
                analog.data = data;
                analog.mq = SR_MQ_VOLTAGE;
@@ -67,42 +73,171 @@ SR_PRIV int rigol_ds1xx2_receive_data(int fd, int revents, void *cb_data)
                packet.type = SR_DF_ANALOG;
                packet.payload = &analog;
                sr_session_send(cb_data, &packet);
+               g_slist_free(analog.probes);
 
-               if (len == WAVEFORM_SIZE) {
-                       /* End of the frame. */
-                       packet.type = SR_DF_FRAME_END;
-                       sr_session_send(sdi, &packet);
+               if (len != WAVEFORM_SIZE)
+                       /* Don't have the whole frame yet. */
+                       return TRUE;
 
-                       if (++devc->num_frames == devc->limit_frames)
+               /* End of the frame. */
+               packet.type = SR_DF_FRAME_END;
+               sr_session_send(sdi, &packet);
+
+               if (devc->channel_frame == devc->enabled_probes->data
+                               && devc->enabled_probes->next != NULL) {
+                       /* We got the frame for the first channel, but
+                        * there's a second channel. */
+                       devc->channel_frame = devc->enabled_probes->next->data;
+                       rigol_ds1xx2_send(devc, ":WAV:DATA? CHAN%c",
+                                       devc->channel_frame->name[2]);
+               } else {
+                       /* Done with both channels in this frame. */
+                       if (++devc->num_frames == devc->limit_frames) {
                                sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       else
-                               rigol_ds1xx2_send_data(fd, ":WAV:DATA?");
+                       } else {
+                               /* Get the next frame, starting with the first channel. */
+                               devc->channel_frame = devc->enabled_probes->data;
+                               rigol_ds1xx2_send(devc, ":WAV:DATA? CHAN%c",
+                                               devc->channel_frame->name[2]);
+                       }
                }
        }
 
        return TRUE;
 }
 
-SR_PRIV int rigol_ds1xx2_send_data(int fd, const char *format, ...)
+SR_PRIV int rigol_ds1xx2_send(struct dev_context *devc, const char *format, ...)
 {
        va_list args;
        char buf[256];
        int len, out, ret;
 
        va_start(args, format);
-       len = vsprintf(buf, format, args);
+       len = vsnprintf(buf, 255, format, args);
        va_end(args);
        strcat(buf, "\n");
        len++;
-       out = write(fd, buf, len);
+       out = write(devc->fd, buf, len);
        buf[len - 1] = '\0';
        if (out != len) {
                sr_dbg("Only sent %d/%d bytes of '%s'.", out, len, buf);
                ret = SR_ERR;
        } else {
-               sr_dbg("Sent '%s'.", buf);
+               sr_spew("Sent '%s'.", buf);
                ret = SR_OK;
        }
 
        return ret;
 }
+
+static int get_cfg(const struct sr_dev_inst *sdi, char *cmd, char *reply)
+{
+       struct dev_context *devc;
+       int len;
+
+       devc = sdi->priv;
+
+       if (rigol_ds1xx2_send(devc, cmd) != SR_OK)
+               return SR_ERR;
+
+       if ((len = read(devc->fd, reply, 255)) < 0)
+               return SR_ERR;
+       reply[len] = '\0';
+       sr_spew("Received '%s'.", reply);
+
+       return SR_OK;
+}
+
+static int get_cfg_float(const struct sr_dev_inst *sdi, char *cmd, float *f)
+{
+       char buf[256], *e;
+
+       if (get_cfg(sdi, cmd, buf) != SR_OK)
+               return SR_ERR;
+       *f = strtof(buf, &e);
+       if (e == buf || (fpclassify(*f) & (FP_ZERO|FP_NORMAL)) == 0) {
+               sr_dbg("failed to parse response to '%s': '%s'", cmd, buf);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int get_cfg_string(const struct sr_dev_inst *sdi, char *cmd, char **buf)
+{
+
+       if (!(*buf = g_try_malloc0(256)))
+               return SR_ERR;
+
+       if (get_cfg(sdi, cmd, *buf) != SR_OK)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+SR_PRIV int rigol_ds1xx2_get_dev_cfg(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       char *t_s;
+
+       devc = sdi->priv;
+
+       /* Channel state. */
+       if (get_cfg_string(sdi, ":CHAN1:DISP?", &t_s) != SR_OK)
+               return SR_ERR;
+       devc->channels[0] = !strcmp(t_s, "ON") ? TRUE : FALSE;
+       g_free(t_s);
+       if (get_cfg_string(sdi, ":CHAN2:DISP?", &t_s) != SR_OK)
+               return SR_ERR;
+       devc->channels[1] = !strcmp(t_s, "ON") ? TRUE : FALSE;
+       g_free(t_s);
+       sr_dbg("Current channel state CH1 %s CH2 %s",
+                       devc->channels[0] ? "on" : "off",
+                       devc->channels[1] ? "on" : "off");
+
+       /* Timebase. */
+       if (get_cfg_float(sdi, ":TIM:SCAL?", &devc->timebase) != SR_OK)
+               return SR_ERR;
+       sr_dbg("Current timebase %f", 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]);
+
+       /* 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],
+                       devc->vert_offset[1]);
+
+       /* Coupling. */
+       if (get_cfg_string(sdi, ":CHAN1:COUP?", &devc->coupling[0]) != SR_OK)
+               return SR_ERR;
+       if (get_cfg_string(sdi, ":CHAN2:COUP?", &devc->coupling[1]) != SR_OK)
+               return SR_ERR;
+       sr_dbg("Current coupling CH1 %s CH2 %s", devc->coupling[0],
+                       devc->coupling[1]);
+
+       /* Trigger source. */
+       if (get_cfg_string(sdi, ":TRIG:EDGE:SOUR?", &devc->trigger_source) != SR_OK)
+               return SR_ERR;
+       sr_dbg("Current trigger source %s", devc->trigger_source);
+
+       /* 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);
+
+       /* Trigger slope. */
+       if (get_cfg_string(sdi, ":TRIG:EDGE:SLOP?", &devc->trigger_slope) != SR_OK)
+               return SR_ERR;
+       sr_dbg("Current trigger slope %s", devc->trigger_slope);
+
+       return SR_OK;
+}
+