X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=blobdiff_plain;f=pv%2Fdata%2Fmathsignal.cpp;h=f7de2ff29103a0662e1dce62a74cb33a8372203c;hp=2217bffd9543ff22320ef0992d2350482f316d42;hb=2823de2c821f01b9b6d8df7fc972e290518075ae;hpb=5a8f700cd1adfcfc316393969d11fba8173e9bbf diff --git a/pv/data/mathsignal.cpp b/pv/data/mathsignal.cpp index 2217bffd..f7de2ff2 100644 --- a/pv/data/mathsignal.cpp +++ b/pv/data/mathsignal.cpp @@ -67,12 +67,18 @@ struct fnc_sample : public exprtk::igeneric_function const scalar_t exprtk_sample_num = scalar_t(parameters[1]); const std::string str_sig_name = to_str(exprtk_sig_name); - const double sample_num = std::max(exprtk_sample_num(), (double)0); + const double sample_num = exprtk_sample_num(); + + if (sample_num < 0) + return 0; if (!sig_data) sig_data = owner_.signal_from_name(str_sig_name); - assert(sig_data); + if (!sig_data) + // There doesn't actually exist a signal with that name + return 0; + owner_.update_signal_sample(sig_data, current_segment, sample_num); return T(sig_data->sample_value); @@ -288,6 +294,8 @@ void MathSignal::reset_generation() // TODO Emulate noquote() qDebug().nospace() << name() << ": Error cleared"; } + + generation_chunk_size_ = ChunkLength; } void MathSignal::begin_generation() @@ -307,6 +315,7 @@ void MathSignal::begin_generation() exprtk_unknown_symbol_table_ = new exprtk::symbol_table(); exprtk_symbol_table_ = new exprtk::symbol_table(); + exprtk_symbol_table_->add_constant("T", 1 / session_.get_samplerate()); exprtk_symbol_table_->add_function("sample", *fnc_sample_); exprtk_symbol_table_->add_variable("t", exprtk_current_time_); exprtk_symbol_table_->add_variable("s", exprtk_current_sample_); @@ -347,7 +356,7 @@ void MathSignal::begin_generation() signal_data* sig_data = signal_from_name(unknown); const shared_ptr signal = (sig_data) ? (sig_data->sb) : nullptr; if (!signal || (!signal->analog_data())) { - set_error(MATH_ERR_INVALID_SIGNAL, QString(tr("%1 isn't a valid analog signal")) \ + set_error(MATH_ERR_INVALID_SIGNAL, QString(tr("\"%1\" isn't a valid analog signal")) \ .arg(QString::fromStdString(unknown))); } else sig_data->ref = &(exprtk_unknown_symbol_table_->variable_ref(unknown)); @@ -370,9 +379,11 @@ void MathSignal::begin_generation() } } -void MathSignal::generate_samples(uint32_t segment_id, const uint64_t start_sample, +uint64_t MathSignal::generate_samples(uint32_t segment_id, const uint64_t start_sample, const int64_t sample_count) { + uint64_t count = 0; + shared_ptr analog = dynamic_pointer_cast(data_); shared_ptr segment = analog->analog_segments().at(segment_id); @@ -396,11 +407,20 @@ void MathSignal::generate_samples(uint32_t segment_id, const uint64_t start_samp double value = exprtk_expression_->value(); sample_data[i] = value; exprtk_current_sample_ += 1; + count++; + + // If during the evaluation of the expression it was found that this + // math signal itself is being accessed, the chunk size was reduced + // to 1, which means we must stop after this sample we just generated + if (generation_chunk_size_ == 1) + break; } - segment->append_interleaved_samples(sample_data, sample_count, 1); + segment->append_interleaved_samples(sample_data, count, 1); delete[] sample_data; + + return count; } void MathSignal::generation_proc() @@ -440,15 +460,13 @@ void MathSignal::generation_proc() // Process the samples if necessary... if (samples_to_process > 0) { - const uint64_t chunk_sample_count = ChunkLength; - uint64_t processed_samples = 0; do { const uint64_t start_sample = output_sample_count + processed_samples; - const uint64_t sample_count = - min(samples_to_process - processed_samples, chunk_sample_count); + uint64_t sample_count = + min(samples_to_process - processed_samples, generation_chunk_size_); - generate_samples(segment_id, start_sample, sample_count); + sample_count = generate_samples(segment_id, start_sample, sample_count); processed_samples += sample_count; // Notify consumers of this signal's data @@ -477,6 +495,12 @@ void MathSignal::generation_proc() signal_data* MathSignal::signal_from_name(const std::string& name) { + // If the expression contains the math signal itself, we must add every sample to + // the output segment immediately so that it can be accessed + const QString sig_name = QString::fromStdString(name); + if (sig_name == this->name()) + generation_chunk_size_ = 1; + // Look up signal in the map and if it doesn't exist yet, add it for future use auto element = input_signals_.find(name); @@ -485,7 +509,6 @@ signal_data* MathSignal::signal_from_name(const std::string& name) return &(element->second); } else { const vector< shared_ptr > signalbases = session_.signalbases(); - const QString sig_name = QString::fromStdString(name); for (const shared_ptr& sb : signalbases) if (sb->name() == sig_name) { @@ -504,6 +527,11 @@ signal_data* MathSignal::signal_from_name(const std::string& name) } } + // If we reach this point, no valid signal was found with the supplied name + if (error_type_ == MATH_ERR_NONE) + set_error(MATH_ERR_INVALID_SIGNAL, QString(tr("\"%1\" isn't a valid analog signal")) \ + .arg(QString::fromStdString(name))); + return nullptr; } @@ -524,7 +552,11 @@ void MathSignal::update_signal_sample(signal_data* sig_data, uint32_t segment_id const shared_ptr segment = analog->analog_segments().at(segment_id); sig_data->sample_num = sample_num; - sig_data->sample_value = segment->get_sample(sample_num); + + if (sample_num < segment->get_sample_count()) + sig_data->sample_value = segment->get_sample(sample_num); + else + sig_data->sample_value = 0; // We only have a reference if this signal is used as a scalar; // if it's used by a function, it's null