diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 55624719..559ed53c 100644 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -188,6 +188,8 @@ QList 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 > &snapshots = - _logic_data->get_snapshots(); - if(snapshots.empty()) + boost::shared_ptr snapshot; + int channel_type; + + if (_dev_inst->dev_inst()->mode == LOGIC) { + const deque< boost::shared_ptr > &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 > &snapshots = + _dso_data->get_snapshots(); + if(snapshots.empty()) + return; + snapshot = snapshots.front(); + channel_type = SR_CHANNEL_DSO; + } else { return; - const boost::shared_ptr & 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 s, _signals) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(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 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 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 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 3bf4c185..9efc9cf7 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 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 a41efb0c..9cd58bdb 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 > sigs(_view.session().get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { diff --git a/libsigrok4DSL/hardware/DSL/dscope.c b/libsigrok4DSL/hardware/DSL/dscope.c index 37f5aa94..d4be1a7c 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 7a7a406f..01f017a3 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 d0edced4..1836bf25 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 7cadb0a0..3617b61f 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 ad37fc98..55cf38ed 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 1b05ebc4..24b5e380 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