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);
// TODO Emulate noquote()
qDebug().nospace() << name() << ": Error cleared";
}
+
+ generation_chunk_size_ = ChunkLength;
}
void MathSignal::begin_generation()
exprtk_unknown_symbol_table_ = new exprtk::symbol_table<double>();
exprtk_symbol_table_ = new exprtk::symbol_table<double>();
+ 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_);
signal_data* sig_data = signal_from_name(unknown);
const shared_ptr<SignalBase> 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));
}
}
-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> analog = dynamic_pointer_cast<Analog>(data_);
shared_ptr<AnalogSegment> segment = analog->analog_segments().at(segment_id);
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()
// 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
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);
return &(element->second);
} else {
const vector< shared_ptr<SignalBase> > signalbases = session_.signalbases();
- const QString sig_name = QString::fromStdString(name);
for (const shared_ptr<SignalBase>& sb : signalbases)
if (sb->name() == sig_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;
}
const shared_ptr<AnalogSegment> 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