diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp
index 5562471942f8be074142298f796b2b7135415644..559ed53c8b3bd4795e075a7cb1f7e3b9661de989 100644
--- a/DSView/pv/sigsession.cpp
+++ b/DSView/pv/sigsession.cpp
@@ -188,6 +188,8 @@ QList<QString> SigSession::getSuportedExportFormats(){
     while(*supportedModules){
         if(*supportedModules == NULL)
             break;
+        if (_dev_inst->dev_inst()->mode == DSO && strcmp((*supportedModules)->id, "csv"))
+            break;
         QString format((*supportedModules)->desc);
         format.append(" (*.");
         format.append((*supportedModules)->id);
@@ -203,12 +205,27 @@ void SigSession::cancelSaveFile(){
 }
 
 void SigSession::export_file(const std::string &name, QWidget* parent, const std::string &ext){
-    const deque< boost::shared_ptr<pv::data::LogicSnapshot> > &snapshots =
-            _logic_data->get_snapshots();
-    if(snapshots.empty())
+    boost::shared_ptr<pv::data::Snapshot> snapshot;
+    int channel_type;
+
+    if (_dev_inst->dev_inst()->mode == LOGIC) {
+        const deque< boost::shared_ptr<pv::data::LogicSnapshot> > &snapshots =
+                _logic_data->get_snapshots();
+        if(snapshots.empty())
+            return;
+        snapshot = snapshots.front();
+        channel_type = SR_CHANNEL_LOGIC;
+    } else if (_dev_inst->dev_inst()->mode == DSO) {
+        const deque< boost::shared_ptr<pv::data::DsoSnapshot> > &snapshots =
+                _dso_data->get_snapshots();
+        if(snapshots.empty())
+            return;
+        snapshot = snapshots.front();
+        channel_type = SR_CHANNEL_DSO;
+    } else {
         return;
-    const boost::shared_ptr<pv::data::LogicSnapshot> & snapshot =
-            snapshots.front();
+    }
+
     const struct sr_output_module** supportedModules = sr_output_list();
     const struct sr_output_module* outModule = NULL;
     while(*supportedModules){
@@ -222,10 +239,23 @@ void SigSession::export_file(const std::string &name, QWidget* parent, const std
     }
     if(outModule == NULL)
         return;
-    struct sr_output output;
+
+
     GHashTable *params = g_hash_table_new(g_str_hash, g_str_equal);
     GVariant* filenameGVariant = g_variant_new_string(name.c_str());
     g_hash_table_insert(params, (char*)"filename", filenameGVariant);
+    GVariant* typeGVariant = g_variant_new_int16(channel_type);
+    g_hash_table_insert(params, (char*)"type", typeGVariant);
+    BOOST_FOREACH(const boost::shared_ptr<view::Signal> s, _signals) {
+        boost::shared_ptr<view::DsoSignal> dsoSig;
+        if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(s)) {
+            GVariant* timebaseGVariant = g_variant_new_uint64(dsoSig->get_hDialValue());
+            g_hash_table_insert(params, (char*)"timebase", timebaseGVariant);
+            break;
+        }
+    }
+
+    struct sr_output output;
     output.module = (sr_output_module*) outModule;
     output.sdi = _dev_inst->dev_inst();
     output.param = NULL;
@@ -234,33 +264,64 @@ void SigSession::export_file(const std::string &name, QWidget* parent, const std
     QFile file(name.c_str());
     file.open(QIODevice::WriteOnly | QIODevice::Text);
     QTextStream out(&file);
-    QFuture<void> future = QtConcurrent::run([&]{
-        saveFileThreadRunning = true;
-        unsigned char* datat = (unsigned char*)snapshot->get_data();
-        unsigned int numsamples = snapshot->get_sample_count()*snapshot->unit_size();
-        GString *data_out;
-        int usize = 8192;
-        int size = usize;
-        struct sr_datafeed_logic lp;
-        struct sr_datafeed_packet p;
-        for(uint64_t i = 0; i < numsamples; i+=usize){
-            if(numsamples - i < usize)
-                size = numsamples - i;
-            lp.data = &datat[i];
-            lp.length = size;
-            lp.unitsize = snapshot->unit_size();
-            p.type = SR_DF_LOGIC;
-            p.payload = &lp;
-            outModule->receive(&output, &p, &data_out);
-            if(data_out){
-                out << (char*) data_out->str;
-                g_string_free(data_out,TRUE);
+    QFuture<void> future;
+    if (_dev_inst->dev_inst()->mode == LOGIC) {
+        future = QtConcurrent::run([&]{
+            saveFileThreadRunning = true;
+            unsigned char* datat = (unsigned char*)snapshot->get_data();
+            unsigned int numsamples = snapshot->get_sample_count()*snapshot->unit_size();
+            GString *data_out;
+            int usize = 8192;
+            int size = usize;
+            struct sr_datafeed_logic lp;
+            struct sr_datafeed_packet p;
+            for(uint64_t i = 0; i < numsamples; i+=usize){
+                if(numsamples - i < usize)
+                    size = numsamples - i;
+                lp.data = &datat[i];
+                lp.length = size;
+                lp.unitsize = snapshot->unit_size();
+                p.type = SR_DF_LOGIC;
+                p.payload = &lp;
+                outModule->receive(&output, &p, &data_out);
+                if(data_out){
+                    out << (char*) data_out->str;
+                    g_string_free(data_out,TRUE);
+                }
+                emit  progressSaveFileValueChanged(i*100/numsamples);
+                if(!saveFileThreadRunning)
+                    break;
             }
-            emit  progressSaveFileValueChanged(i*100/numsamples);
-            if(!saveFileThreadRunning)
-                break;
-        }
-    });
+        });
+    } else if (_dev_inst->dev_inst()->mode == DSO) {
+        future = QtConcurrent::run([&]{
+            saveFileThreadRunning = true;
+            unsigned char* datat = (unsigned char*)snapshot->get_data();
+            unsigned int numsamples = snapshot->get_sample_count();
+            GString *data_out;
+            int usize = 8192;
+            int size = usize;
+            struct sr_datafeed_dso dp;
+            struct sr_datafeed_packet p;
+            for(uint64_t i = 0; i < numsamples; i+=usize){
+                if(numsamples - i < usize)
+                    size = numsamples - i;
+                dp.data = &datat[i*snapshot->get_channel_num()];
+                dp.num_samples = size;
+                p.type = SR_DF_DSO;
+                p.payload = &dp;
+                outModule->receive(&output, &p, &data_out);
+                if(data_out){
+                    out << (char*) data_out->str;
+                    g_string_free(data_out,TRUE);
+                }
+                emit  progressSaveFileValueChanged(i*100/numsamples);
+                if(!saveFileThreadRunning)
+                    break;
+            }
+        });
+    }
+
     QFutureWatcher<void> watcher;
     Qt::WindowFlags flags = Qt::CustomizeWindowHint;
     QProgressDialog dlg(QString::fromUtf8("Exporting data... It can take a while."),
diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp
index 3bf4c185139b7b9f8f45caf893fdfa451e3eb29c..9efc9cf757a7e4560aa32441c4946cba704f2e22 100644
--- a/DSView/pv/toolbars/filebar.cpp
+++ b/DSView/pv/toolbars/filebar.cpp
@@ -127,14 +127,7 @@ void FileBar::on_actionExport_triggered(){
         msg.setStandardButtons(QMessageBox::Ok);
         msg.setIcon(QMessageBox::Warning);
         msg.exec();
-    } else if (_session.get_device()->dev_inst()->mode != LOGIC) {
-        QMessageBox msg(this);
-        msg.setText("Export Data");
-        msg.setInformativeText("DSLogic currently only support exporting logic data to file!");
-        msg.setStandardButtons(QMessageBox::Ok);
-        msg.setIcon(QMessageBox::Warning);
-        msg.exec();
-    }else {
+    } else {
         QList<QString> supportedFormats = _session.getSuportedExportFormats();
         QString filter;
         for(int i = 0; i < supportedFormats.count();i++){
diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp
index a41efb0c5930557cc6d78ec90029fe0452ae1b4f..9cd58bdb5b131b7dd82272cc7428d4e9894d2d03 100644
--- a/DSView/pv/view/viewport.cpp
+++ b/DSView/pv/view/viewport.cpp
@@ -503,6 +503,8 @@ void Viewport::set_receive_len(quint64 length)
 
 void Viewport::measure()
 {
+   if (_view.session().get_capture_state() == SigSession::Running)
+       return;
    const uint64_t sample_rate = _view.session().get_device()->get_sample_rate();
    const vector< boost::shared_ptr<Signal> > sigs(_view.session().get_signals());
    BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
diff --git a/libsigrok4DSL/hardware/DSL/dscope.c b/libsigrok4DSL/hardware/DSL/dscope.c
index 37f5aa94e55ab7046b9a8f708fc29eb140c12f7e..d4be1a7cb94335212a30c284ac32b67bbb4995ef 100644
--- a/libsigrok4DSL/hardware/DSL/dscope.c
+++ b/libsigrok4DSL/hardware/DSL/dscope.c
@@ -601,6 +601,7 @@ static int set_probes(struct sr_dev_inst *sdi, int num_probes)
             return SR_ERR;
         if (sdi->mode == DSO) {
             probe->vdiv = 1000;
+            probe->vfactor = 1;
             probe->vpos = 0;
             probe->coupling = SR_DC_COUPLING;
             probe->trig_value = 0x80;
diff --git a/libsigrok4DSL/hardware/DSL/dslogic.c b/libsigrok4DSL/hardware/DSL/dslogic.c
index 7a7a406fb1f9e0a6d9a2eab524e816e0f5eb1511..01f017a39e340eef566ddf11d077a036fdd5a733 100644
--- a/libsigrok4DSL/hardware/DSL/dslogic.c
+++ b/libsigrok4DSL/hardware/DSL/dslogic.c
@@ -642,6 +642,7 @@ static int set_probes(struct sr_dev_inst *sdi, int num_probes)
             return SR_ERR;
         if (sdi->mode == DSO) {
             probe->vdiv = 1000;
+            probe->vfactor = 1;
             probe->coupling = SR_DC_COUPLING;
             probe->trig_value = 0x80;
         }
diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h
index d0edced45f9a539d0a70c638cc4355fbeb032fa4..1836bf25bc2e7b516936d3b74ecc5a710eb15a2f 100644
--- a/libsigrok4DSL/libsigrok.h
+++ b/libsigrok4DSL/libsigrok.h
@@ -323,7 +323,7 @@ struct sr_datafeed_dso {
     uint64_t mqflags;
     /** The analog value(s). The data is interleaved according to
      * the probes list. */
-    float *data;
+    void *data;
 };
 
 struct sr_datafeed_analog {
@@ -559,6 +559,7 @@ struct sr_channel {
 	char *name;
 	char *trigger;
     uint64_t vdiv;
+    uint16_t vfactor;
     double vpos;
     uint8_t coupling;
     uint8_t trig_value;
diff --git a/libsigrok4DSL/output/csv.c b/libsigrok4DSL/output/csv.c
index 7cadb0a0065809001c7adccc6bf47ebd44e3aed0..3617b61f393ca6a3f1e7f7bbb7ae2e1359f44e76 100644
--- a/libsigrok4DSL/output/csv.c
+++ b/libsigrok4DSL/output/csv.c
@@ -33,9 +33,13 @@ struct context {
 	char separator;
 	gboolean header_done;
 	int *channel_index;
+    float *channel_vdiv;
+    double *channel_vpos;
+    uint64_t timebase;
     uint64_t mask;
     uint64_t pre_data;
     uint64_t index;
+    int type;
 };
 
 /*
@@ -57,8 +61,6 @@ static int init(struct sr_output *o, GHashTable *options)
 	GSList *l;
 	int i;
 
-	(void)options;
-
 	if (!o || !o->sdi)
 		return SR_ERR_ARG;
 
@@ -67,27 +69,34 @@ static int init(struct sr_output *o, GHashTable *options)
 	ctx->separator = ',';
     ctx->mask = 0;
     ctx->index = 0;
+    ctx->type = g_variant_get_int16(g_hash_table_lookup(options, "type"));
+    ctx->timebase = g_variant_get_uint64(g_hash_table_lookup(options, "timebase"));
 
 	/* Get the number of channels, and the unitsize. */
 	for (l = o->sdi->channels; l; l = l->next) {
 		ch = l->data;
-		if (ch->type != SR_CHANNEL_LOGIC)
+        if (ch->type != ctx->type)
 			continue;
 		if (!ch->enabled)
 			continue;
 		ctx->num_enabled_channels++;
 	}
 	ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+    ctx->channel_vdiv = g_malloc(sizeof(float) * ctx->num_enabled_channels);
+    ctx->channel_vpos = g_malloc(sizeof(double) * ctx->num_enabled_channels);
 
 	/* Once more to map the enabled channels. */
 	for (i = 0, l = o->sdi->channels; l; l = l->next) {
 		ch = l->data;
-		if (ch->type != SR_CHANNEL_LOGIC)
+        if (ch->type != ctx->type)
 			continue;
 		if (!ch->enabled)
 			continue;
-		ctx->channel_index[i++] = ch->index;
+        ctx->channel_index[i] = ch->index;
         ctx->mask |= (1 << ch->index);
+        ctx->channel_vdiv[i] = ch->vdiv * ch->vfactor >= 500 ? ch->vdiv * ch->vfactor / 100.0f : ch->vdiv * ch->vfactor * 10.0f;
+        ctx->channel_vpos[i] = ch->vdiv * ch->vfactor >= 500 ? ch->vpos / 1000 : ch->vpos;
+        i++;
 	}
 
 	return SR_OK;
@@ -102,7 +111,6 @@ static GString *gen_header(const struct sr_output *o)
 	GSList *l;
 	time_t t;
 	int num_channels, i;
-	char *samplerate_s;
 
 	ctx = o->priv;
 	header = g_string_sized_new(512);
@@ -113,7 +121,10 @@ static GString *gen_header(const struct sr_output *o)
 			PACKAGE_STRING, ctime(&t));
 
 	/* Columns / channels */
-	num_channels = g_slist_length(o->sdi->channels);
+    if (ctx->type == SR_CHANNEL_LOGIC)
+        num_channels = g_slist_length(o->sdi->channels);
+    else
+        num_channels = ctx->num_enabled_channels;
     g_string_append_printf(header, "; Channels (%d/%d)\n",
 			ctx->num_enabled_channels, num_channels);
 
@@ -125,19 +136,34 @@ static GString *gen_header(const struct sr_output *o)
 		}
 	}
 	if (ctx->samplerate != 0) {
-		samplerate_s = sr_samplerate_string(ctx->samplerate);
-		g_string_append_printf(header, "; Samplerate: %s\n", samplerate_s);
+        char *samplerate_s = sr_samplerate_string(ctx->samplerate);
+        g_string_append_printf(header, "; Sample rate: %s\n", samplerate_s);
 		g_free(samplerate_s);
 	}
 
-    g_string_append_printf(header, "Time(s),");
+    if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_LIMIT_SAMPLES,
+            &gvar) == SR_OK) {
+        uint64_t depth = g_variant_get_uint64(gvar);
+        g_variant_unref(gvar);
+        char *depth_s = sr_samplecount_string(depth);
+        g_string_append_printf(header, "; Sample count: %s\n", depth_s);
+        g_free(depth_s);
+    }
+
+    if (ctx->type == SR_CHANNEL_LOGIC)
+        g_string_append_printf(header, "Time(s),");
     for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
         ch = l->data;
-        if (ch->type != SR_CHANNEL_LOGIC)
+        if (ch->type != ctx->type)
             continue;
         if (!ch->enabled)
             continue;
-        g_string_append_printf(header, " %s,", ch->name);
+        if (ctx->type == SR_CHANNEL_DSO) {
+            char *unit_s = (ch->vdiv * ch->vfactor) >= 500 ? "V" : "mV";
+            g_string_append_printf(header, " %s (Unit: %s),", ch->name, unit_s);
+        } else {
+            g_string_append_printf(header, " %s,", ch->name);
+        }
     }
     if (o->sdi->channels)
         /* Drop last separator. */
@@ -152,12 +178,13 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p
 {
 	const struct sr_datafeed_meta *meta;
 	const struct sr_datafeed_logic *logic;
+    const struct sr_datafeed_dso *dso;
 	const struct sr_config *src;
 	GSList *l;
 	struct context *ctx;
 	int idx;
 	uint64_t i, j;
-	gchar *p, c;
+    unsigned char *p, c;
 
 	*out = NULL;
 	if (!o || !o->sdi)
@@ -200,6 +227,28 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p
             ctx->pre_data = (*(uint64_t *)(logic->data + i) & ctx->mask);
 		}
 		break;
+     case SR_DF_DSO:
+        dso = packet->payload;
+        if (!ctx->header_done) {
+            *out = gen_header(o);
+            ctx->header_done = TRUE;
+        } else {
+            *out = g_string_sized_new(512);
+        }
+
+        for (i = 0; i < dso->num_samples; i++) {
+            for (j = 0; j < ctx->num_enabled_channels; j++) {
+                idx = ctx->channel_index[j];
+                p = dso->data + i * ctx->num_enabled_channels + idx * ((ctx->num_enabled_channels > 1) ? 1 : 0);
+                g_string_append_printf(*out, "%0.2f", (128 - *p) * ctx->channel_vdiv[j] / 255 - ctx->channel_vpos[j]);
+                g_string_append_c(*out, ctx->separator);
+            }
+
+            /* Drop last separator. */
+            g_string_truncate(*out, (*out)->len - 1);
+            g_string_append_printf(*out, "\n");
+        }
+        break;
 	}
 
 	return SR_OK;
diff --git a/libsigrok4DSL/proto.h b/libsigrok4DSL/proto.h
index ad37fc98cfaaa4e5ec48f80cae059851d7084d06..55cf38ed14f66ffe61f24875f771cd1df7cbf69f 100644
--- a/libsigrok4DSL/proto.h
+++ b/libsigrok4DSL/proto.h
@@ -141,6 +141,7 @@ SR_API char *sr_iec_string_u64(uint64_t x, const char *unit);
 SR_API char *sr_samplerate_string(uint64_t samplerate);
 SR_API char *sr_samplecount_string(uint64_t samplecount);
 SR_API char *sr_period_string(uint64_t frequency);
+SR_API char *sr_time_string(uint64_t time);
 SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q);
 SR_API char **sr_parse_triggerstring(const struct sr_dev_inst *sdi,
 		const char *triggerstring);
diff --git a/libsigrok4DSL/strutil.c b/libsigrok4DSL/strutil.c
index 1b05ebc469ceb84b671137acdaaaad15f6467e53..24b5e380e92988b774d5ac6a6f8bee788e12e8c7 100644
--- a/libsigrok4DSL/strutil.c
+++ b/libsigrok4DSL/strutil.c
@@ -211,6 +211,47 @@ SR_API char *sr_period_string(uint64_t frequency)
 	return o;
 }
 
+/**
+ * Convert a numeric time(ns) value to the "natural" string representation
+ * of its period.
+ *
+ * E.g. a value of 3000000 would be converted to "3 ms", 20000 to "20 us".
+ *
+ * @param time The time in ns.
+ *
+ * @return A g_try_malloc()ed string representation of the time value,
+ *         or NULL upon errors. The caller is responsible to g_free() the
+ *         memory.
+ */
+SR_API char *sr_time_string(uint64_t time)
+{
+    char *o;
+    int r;
+
+    /* Allocate enough for a uint64_t as string + " ms". */
+    if (!(o = g_try_malloc0(30 + 1))) {
+        sr_err("%s: o malloc failed", __func__);
+        return NULL;
+    }
+
+    if (time >= 1000000000)
+        r = snprintf(o, 30, "%" PRIu64 " s", time / 1000000000);
+    else if (time >= 1000000)
+        r = snprintf(o, 30, "%" PRIu64 " ms", time / 1000000);
+    else if (time >= 1000)
+        r = snprintf(o, 30, "%" PRIu64 " us", time / 1000);
+    else
+        r = snprintf(o, 30, "%" PRIu64 " ns", time);
+
+    if (r < 0) {
+        /* Something went wrong... */
+        g_free(o);
+        return NULL;
+    }
+
+    return o;
+}
+
 /**
  * Convert a numeric voltage value to the "natural" string representation
  * of its voltage value. The voltage is specified as a rational number's