namespace pv {
namespace data {
+#define MATH_ERR_NONE 0
+#define MATH_ERR_EMPTY_EXPR 1
+#define MATH_ERR_EXPRESSION 2
+#define MATH_ERR_INVALID_SIGNAL 3
+#define MATH_ERR_ENABLE 4
+
const int64_t MathSignal::ChunkLength = 256 * 1024;
template<typename T>
-struct sig_sample : public exprtk::igeneric_function<T>
+struct fnc_sample : public exprtk::igeneric_function<T>
{
typedef typename exprtk::igeneric_function<T>::parameter_list_t parameter_list_t;
typedef typename exprtk::igeneric_function<T>::generic_type generic_type;
typedef typename generic_type::scalar_view scalar_t;
typedef typename generic_type::string_view string_t;
- sig_sample(MathSignal& owner) :
+ fnc_sample(MathSignal& owner) :
exprtk::igeneric_function<T>("ST"), // Require channel name and sample number
owner_(owner),
sig_data(nullptr)
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 = exprtk_sample_num();
+ const double sample_num = std::max(exprtk_sample_num(), (double)0);
if (!sig_data)
sig_data = owner_.signal_from_name(str_sig_name);
use_custom_sample_rate_(false),
use_custom_sample_count_(false),
expression_(""),
+ error_type_(MATH_ERR_NONE),
exprtk_unknown_symbol_table_(nullptr),
exprtk_symbol_table_(nullptr),
exprtk_expression_(nullptr),
exprtk_parser_(nullptr),
- fnc_sig_sample_(nullptr)
+ fnc_sample_(nullptr)
{
uint32_t sig_idx = session_.get_next_signal_index(MathChannel);
set_name(QString(tr("Math%1")).arg(sig_idx));
MathSignal::~MathSignal()
{
reset_generation();
-
- if (fnc_sig_sample_)
- delete fnc_sig_sample_;
}
void MathSignal::save_settings(QSettings &settings) const
{
+ SignalBase::save_settings(settings);
+
settings.setValue("expression", expression_);
settings.setValue("custom_sample_rate", (qulonglong)custom_sample_rate_);
void MathSignal::restore_settings(QSettings &settings)
{
+ SignalBase::restore_settings(settings);
+
if (settings.contains("expression"))
expression_ = settings.value("expression").toString();
begin_generation();
}
-void MathSignal::set_error_message(QString msg)
+void MathSignal::set_error(uint8_t type, QString msg)
{
+ error_type_ = type;
error_message_ = msg;
// TODO Emulate noquote()
- qDebug().nospace() << name() << ": " << msg << "(Expression: '" << expression_ << "')";
+ qDebug().nospace() << name() << ": " << msg << "(Expression: '" + expression_ + "')";
error_message_changed(msg);
}
exprtk_unknown_symbol_table_ = nullptr;
}
- if (fnc_sig_sample_) {
- delete fnc_sig_sample_;
- fnc_sig_sample_ = nullptr;
+ if (fnc_sample_) {
+ delete fnc_sample_;
+ fnc_sample_ = nullptr;
}
if (!error_message_.isEmpty()) {
- error_message_ = QString();
+ error_message_.clear();
+ error_type_ = MATH_ERR_NONE;
// TODO Emulate noquote()
qDebug().nospace() << name() << ": Error cleared";
}
reset_generation();
if (expression_.isEmpty()) {
- set_error_message(tr("No expression defined, nothing to do"));
+ set_error(MATH_ERR_EMPTY_EXPR, tr("No expression defined, nothing to do"));
return;
}
disconnect(this, SLOT(on_data_received()));
+ disconnect(this, SLOT(on_enabled_changed()));
- fnc_sig_sample_ = new sig_sample<double>(*this);
+ fnc_sample_ = new fnc_sample<double>(*this);
exprtk_unknown_symbol_table_ = new exprtk::symbol_table<double>();
exprtk_symbol_table_ = new exprtk::symbol_table<double>();
- exprtk_symbol_table_->add_function("sig_sample", *fnc_sig_sample_);
+ 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_);
exprtk_symbol_table_->add_constants();
.arg(error.column_no) \
.arg(error.diagnostic.c_str());
}
- set_error_message(error_details);
+ set_error(MATH_ERR_EXPRESSION, error_details);
} else {
// Resolve unknown scalars to signals and add them to the input signal list
vector<string> unknowns;
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_message(QString(tr("%1 isn't a valid analog signal")).arg(
- QString::fromStdString(unknown)));
+ 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));
}
}
+ QString disabled_signals;
+ if (!all_input_signals_enabled(disabled_signals) && error_message_.isEmpty())
+ set_error(MATH_ERR_ENABLE,
+ tr("No data will be generated as %1 must be enabled").arg(disabled_signals));
+
if (error_message_.isEmpty()) {
// Connect to the session data notification if we have no input signals
if (input_signals_.empty())
shared_ptr<AnalogSegment> segment = analog->analog_segments().at(segment_id);
// Keep the math functions segment IDs in sync
- fnc_sig_sample_->current_segment = segment_id;
+ fnc_sample_->current_segment = segment_id;
const double sample_rate = data_->get_samplerate();
connect(sb->analog_data().get(), SIGNAL(segment_completed()),
this, SLOT(on_data_received()));
+ connect(sb.get(), SIGNAL(enabled_changed(bool)),
+ this, SLOT(on_enabled_changed()));
+
return &(input_signals_.insert({name, signal_data(sb)}).first->second);
}
}
*(sig_data->ref) = sig_data->sample_value;
}
+bool MathSignal::all_input_signals_enabled(QString &disabled_signals) const
+{
+ bool all_enabled = true;
+
+ disabled_signals.clear();
+
+ for (auto input_signal : input_signals_) {
+ const shared_ptr<SignalBase>& sb = input_signal.second.sb;
+
+ if (!sb->enabled()) {
+ all_enabled = false;
+ disabled_signals += disabled_signals.isEmpty() ?
+ sb->name() : ", " + sb->name();
+ }
+ }
+
+ return all_enabled;
+}
+
void MathSignal::on_capture_state_changed(int state)
{
if (state == Session::Running)
gen_input_cond_.notify_one();
}
+void MathSignal::on_enabled_changed()
+{
+ QString disabled_signals;
+ if (!all_input_signals_enabled(disabled_signals) &&
+ ((error_type_ == MATH_ERR_NONE) || (error_type_ == MATH_ERR_ENABLE)))
+ set_error(MATH_ERR_ENABLE,
+ tr("No data will be generated as %1 must be enabled").arg(disabled_signals));
+ else if (disabled_signals.isEmpty() && (error_type_ == MATH_ERR_ENABLE)) {
+ error_type_ = MATH_ERR_NONE;
+ error_message_.clear();
+ }
+}
+
} // namespace data
} // namespace pv