diff --git a/lib/hooks/average.cpp b/lib/hooks/average.cpp index a9e157a6c..be58f2b80 100644 --- a/lib/hooks/average.cpp +++ b/lib/hooks/average.cpp @@ -25,7 +25,6 @@ */ #include - #include #include @@ -36,34 +35,16 @@ namespace villas { namespace node { -class AverageHook : public Hook { +class AverageHook : public MultiSignalHook { protected: unsigned offset; - std::bitset mask; - vlist signal_names; - public: AverageHook(struct vpath *p, struct vnode *n, int fl, int prio, bool en = true) : - Hook(p, n, fl, prio, en), + MultiSignalHook(p, n, fl, prio, en), offset(0) - { - int ret; - - ret = vlist_init(&signal_names); - if (ret) - throw RuntimeError("Failed to intialize list"); - - state = State::INITIALIZED; - } - - virtual ~AverageHook() - { - int ret __attribute__((unused)); - - ret = vlist_destroy(&signal_names, nullptr, true); - } + { } virtual void prepare() { @@ -72,19 +53,7 @@ public: assert(state == State::CHECKED); - /* Setup mask */ - for (size_t i = 0; i < vlist_length(&signal_names); i++) { - char *signal_name = (char *) vlist_at_safe(&signal_names, i); - - int index = vlist_lookup_index(&signals, signal_name); - if (index < 0) - throw RuntimeError("Failed to find signal {}", signal_name); - - mask.set(index); - } - - if (mask.none()) - throw RuntimeError("Invalid signal mask"); + MultiSignalHook::prepare(); /* Add averaged signal */ avg_sig = signal_create("average", nullptr, SignalType::FLOAT); @@ -101,39 +70,18 @@ public: virtual void parse(json_t *json) { int ret; - size_t i; json_error_t err; - json_t *json_signals, *json_signal; assert(state != State::STARTED); - Hook::parse(json); + MultiSignalHook::parse(json); - ret = json_unpack_ex(json, &err, 0, "{ s: i, s: o }", - "offset", &offset, - "signals", &json_signals + ret = json_unpack_ex(json, &err, 0, "{ s: i }", + "offset", &offset ); if (ret) throw ConfigError(json, err, "node-config-hook-average"); - if (!json_is_array(json_signals)) - throw ConfigError(json_signals, "node-config-hook-average-signals", "Setting 'signals' must be a list of signal names"); - - json_array_foreach(json_signals, i, json_signal) { - switch (json_typeof(json_signal)) { - case JSON_STRING: - vlist_push(&signal_names, strdup(json_string_value(json_signal))); - break; - - case JSON_INTEGER: - mask.set(json_integer_value(json_signal)); - break; - - default: - throw ConfigError(json_signal, "node-config-hook-average-signals", "Invalid value for setting 'signals'"); - } - } - state = State::PARSED; } @@ -144,17 +92,14 @@ public: assert(state == State::STARTED); - for (unsigned k = 0; k < smp->length; k++) { - if (!mask.test(k)) - continue; - - switch (sample_format(smp, k)) { + for (unsigned index : signalIndices) { + switch (sample_format(smp, index)) { case SignalType::INTEGER: - sum += smp->data[k].i; + sum += smp->data[index].i; break; case SignalType::FLOAT: - sum += smp->data[k].f; + sum += smp->data[index].f; break; case SignalType::INVALID: diff --git a/lib/hooks/cast.cpp b/lib/hooks/cast.cpp index 4cf521646..306bdfe49 100644 --- a/lib/hooks/cast.cpp +++ b/lib/hooks/cast.cpp @@ -33,66 +33,40 @@ namespace villas { namespace node { -class CastHook : public Hook { +class CastHook : public MultiSignalHook { protected: - unsigned signal_index; - char *signal_name; - enum SignalType new_type; - char *new_name; - char *new_unit; + std::string new_name; + std::string new_unit; public: CastHook(struct vpath *p, struct vnode *n, int fl, int prio, bool en = true) : - Hook(p, n, fl, prio, en), - signal_index(-1), - signal_name(nullptr), - new_type(SignalType::INVALID), - new_name(nullptr), - new_unit(nullptr) + MultiSignalHook(p, n, fl, prio, en), + new_type(SignalType::INVALID) { } - ~CastHook() - { - if (signal_name) - free(signal_name); - - if (new_name) - free(new_name); - - if (new_unit) - free(new_unit); - } - virtual void prepare() { struct signal *orig_sig, *new_sig; assert(state == State::CHECKED); - if (signal_name) { - signal_index = vlist_lookup_index(&signals, signal_name); - if (signal_index < 0) - throw RuntimeError("Failed to find signal: {}", signal_name); + MultiSignalHook::prepare(); + + for (auto index : signalIndices) { + orig_sig = (struct signal *) vlist_at_safe(&signals, index); + + auto type = new_type == SignalType::INVALID ? orig_sig->type : new_type; + auto name = new_name.empty() ? orig_sig->name : new_name; + auto unit = new_unit.empty() ? orig_sig->unit : new_unit; + + new_sig = signal_create(name.c_str(), unit.c_str(), type); + + vlist_set(&signals, index, new_sig); + signal_decref(orig_sig); } - char *name, *unit; - enum SignalType type; - - orig_sig = (struct signal *) vlist_at_safe(&signals, signal_index); - if (!orig_sig) - throw RuntimeError("Failed to find signal: {}", signal_name); - - type = new_type != SignalType::INVALID ? new_type : orig_sig->type; - name = new_name ? new_name : orig_sig->name; - unit = new_unit ? new_unit : orig_sig->unit; - - new_sig = signal_create(name, unit, type); - - vlist_set(&signals, signal_index, new_sig); - signal_decref(orig_sig); - state = State::PREPARED; } @@ -101,18 +75,16 @@ public: int ret; json_error_t err; - json_t *json_signal; assert(state != State::STARTED); - Hook::parse(json); + MultiSignalHook::parse(json); const char *name = nullptr; const char *unit = nullptr; const char *type = nullptr; - ret = json_unpack_ex(json, &err, 0, "{ s: o, s?: s, s?: s, s?: s }", - "signal", &json_signal, + ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: s, s?: s }", "new_type", &type, "new_name", &name, "new_unit", &unit @@ -120,20 +92,6 @@ public: if (ret) throw ConfigError(json, err, "node-config-hook-cast"); - switch (json_typeof(json_signal)) { - case JSON_STRING: - signal_name = strdup(json_string_value(json_signal)); - break; - - case JSON_INTEGER: - signal_name = nullptr; - signal_index = json_integer_value(json_signal); - break; - - default: - throw ConfigError(json_signal, "node-config-hook-cast-signals", "Invalid value for setting 'signal'"); - } - if (type) { new_type = signal_type_from_str(type); if (new_type == SignalType::INVALID) @@ -144,10 +102,10 @@ public: new_type = SignalType::INVALID; if (name) - new_name = strdup(name); + new_name = name; if (unit) - new_unit = strdup(unit); + new_unit = unit; state = State::PARSED; } @@ -156,10 +114,12 @@ public: { assert(state == State::STARTED); - struct signal *orig_sig = (struct signal *) vlist_at(smp->signals, signal_index); - struct signal *new_sig = (struct signal *) vlist_at(&signals, signal_index); + for (auto index : signalIndices) { + struct signal *orig_sig = (struct signal *) vlist_at(smp->signals, index); + struct signal *new_sig = (struct signal *) vlist_at(&signals, index); - signal_data_cast(&smp->data[signal_index], orig_sig->type, new_sig->type); + signal_data_cast(&smp->data[index], orig_sig->type, new_sig->type); + } return Reason::OK; } diff --git a/lib/hooks/gate.cpp b/lib/hooks/gate.cpp index 5303f33eb..156beab60 100644 --- a/lib/hooks/gate.cpp +++ b/lib/hooks/gate.cpp @@ -36,7 +36,7 @@ namespace villas { namespace node { -class GateHook : public Hook { +class GateHook : public SingleSignalHook { protected: enum class Mode { @@ -46,8 +46,6 @@ protected: FALLING_EDGE } mode; - std::string signalName; - int signalIndex; double threshold; double duration; int samples; @@ -59,10 +57,8 @@ protected: public: GateHook(struct vpath *p, struct vnode *n, int fl, int prio, bool en = true) : - Hook(p, n, fl, prio, en), + SingleSignalHook(p, n, fl, prio, en), mode(Mode::RISING_EDGE), - signalName(), - signalIndex(0), threshold(0.5), duration(-1), samples(-1), @@ -76,16 +72,14 @@ public: int ret; json_error_t err; - json_t *json_signal; const char *mode_str; assert(state != State::STARTED); - Hook::parse(json); + SingleSignalHook::parse(json); - ret = json_unpack_ex(json, &err, 0, "{ s: o, s?: F, s?: F, s?: i, s?: s }", - "signal", &json_signal, + ret = json_unpack_ex(json, &err, 0, "{ s?: F, s?: F, s?: i, s?: s }", "threshold", &threshold, "duration", &duration, "samples", &samples, @@ -105,20 +99,6 @@ public: mode = Mode::FALLING_EDGE; } - switch (json_typeof(json_signal)) { - case JSON_STRING: - signalName = json_string_value(json_signal); - break; - - case JSON_INTEGER: - signalName.clear(); - signalIndex = json_integer_value(json_signal); - break; - - default: - throw ConfigError(json_signal, "node-config-hook-cast-signals", "Invalid value for setting 'signal'"); - } - state = State::PARSED; } @@ -126,24 +106,14 @@ public: { assert(state == State::CHECKED); - if (!signalName.empty()) { - signalIndex = vlist_lookup_index(&signals, signalName); - if (signalIndex < 0) - throw RuntimeError("Failed to find signal: {}", signalName); - } - /* Check if signal type is float */ auto sig = (struct signal *) vlist_at(&signals, signalIndex); - if (!sig) - throw RuntimeError("Invalid signal index: {}", signalIndex); - if (sig->type != SignalType::FLOAT) throw RuntimeError("Gate signal must be of type float"); state = State::PREPARED; } - virtual Hook::Reason process(sample *smp) { assert(state == State::STARTED); diff --git a/lib/hooks/limit_value.cpp b/lib/hooks/limit_value.cpp index cd0412182..8ea390fe1 100644 --- a/lib/hooks/limit_value.cpp +++ b/lib/hooks/limit_value.cpp @@ -36,37 +36,20 @@ namespace villas { namespace node { -class LimitValueHook : public Hook { +class LimitValueHook : public MultiSignalHook { protected: unsigned offset; float min, max; - std::bitset mask; - vlist signal_names; - public: LimitValueHook(struct vpath *p, struct vnode *n, int fl, int prio, bool en = true) : - Hook(p, n, fl, prio, en), + MultiSignalHook(p, n, fl, prio, en), offset(0), - min(0), max(0) - { - int ret; - - ret = vlist_init(&signal_names); - if (ret) - throw RuntimeError("Failed to intialize list"); - - state = State::INITIALIZED; - } - - virtual ~LimitValueHook() - { - int ret __attribute__((unused)); - - ret = vlist_destroy(&signal_names, nullptr, true); - } + min(0), + max(0) + { } virtual void prepare() { @@ -75,19 +58,7 @@ public: assert(state == State::CHECKED); - /* Setup mask */ - for (size_t i = 0; i < vlist_length(&signal_names); i++) { - char *signal_name = (char *) vlist_at_safe(&signal_names, i); - - int index = vlist_lookup_index(&signals, signal_name); - if (index < 0) - throw RuntimeError("Failed to find signal {}", signal_name); - - mask.set(index); - } - - if (mask.none()) - throw RuntimeError("Invalid signal mask"); + MultiSignalHook::prepare(); /* Add averaged signal */ avg_sig = signal_create("average", nullptr, SignalType::FLOAT); @@ -104,40 +75,19 @@ public: virtual void parse(json_t *json) { int ret; - size_t i; json_error_t err; - json_t *json_signals, *json_signal; assert(state != State::STARTED); - Hook::parse(json); + MultiSignalHook::parse(json); - ret = json_unpack_ex(json, &err, 0, "{ s: f, s: f, s: o }", + ret = json_unpack_ex(json, &err, 0, "{ s: f, s: f }", "min", &min, - "min", &max, - "signals", &json_signals + "min", &max ); if (ret) throw ConfigError(json, err, "node-config-hook-average"); - if (!json_is_array(json_signals)) - throw ConfigError(json_signals, "node-config-hook-average-signals", "Setting 'signals' must be a list of signal names"); - - json_array_foreach(json_signals, i, json_signal) { - switch (json_typeof(json_signal)) { - case JSON_STRING: - vlist_push(&signal_names, strdup(json_string_value(json_signal))); - break; - - case JSON_INTEGER: - mask.set(json_integer_value(json_signal)); - break; - - default: - throw ConfigError(json_signal, "node-config-hook-average-signals", "Invalid value for setting 'signals'"); - } - } - state = State::PARSED; } @@ -145,25 +95,22 @@ public: { assert(state == State::STARTED); - for (unsigned k = 0; k < smp->length; k++) { - if (!mask.test(k)) - continue; - - switch (sample_format(smp, k)) { + for (auto index : signalIndices) { + switch (sample_format(smp, index)) { case SignalType::INTEGER: - if (smp->data[k].i > max) - smp->data[k].i = max; + if (smp->data[index].i > max) + smp->data[index].i = max; - if (smp->data[k].i < min) - smp->data[k].i = min; + if (smp->data[index].i < min) + smp->data[index].i = min; break; case SignalType::FLOAT: - if (smp->data[k].f > max) - smp->data[k].f = max; + if (smp->data[index].f > max) + smp->data[index].f = max; - if (smp->data[k].f < min) - smp->data[k].f = min; + if (smp->data[index].f < min) + smp->data[index].f = min; break; case SignalType::INVALID: diff --git a/lib/hooks/pps_ts.cpp b/lib/hooks/pps_ts.cpp index 89267c1fa..171e9b347 100644 --- a/lib/hooks/pps_ts.cpp +++ b/lib/hooks/pps_ts.cpp @@ -34,47 +34,45 @@ namespace villas { namespace node { -class PpsTsHook : public Hook { +class PpsTsHook : public SingleSignalHook { protected: double lastValue; - double thresh; - unsigned idx; + double threshold; uint64_t lastSequence; bool isSynced; bool isLocked; struct timespec tsVirt; double timeError; /**< In seconds */ - double periodEst; /**< In seconds */ - double periodErrComp; /**< In seconds */ + double periodEstimate; /**< In seconds */ + double periodErrorCompensation; /**< In seconds */ double period; /**< In seconds */ uintmax_t cntEdges; uintmax_t cntSmps; uintmax_t cntSmpsTotal; - unsigned horizonComp; - unsigned horizonEst; + unsigned horizonCompensation; + unsigned horizonEstimation; std::vector filterWindow; public: PpsTsHook(struct vpath *p, struct vnode *n, int fl, int prio, bool en = true) : - Hook(p, n, fl, prio, en), + SingleSignalHook(p, n, fl, prio, en), lastValue(0), - thresh(1.5), - idx(0), + threshold(1.5), lastSequence(0), isSynced(false), isLocked(false), timeError(0.0), - periodEst(0.0), - periodErrComp(0.0), + periodEstimate(0.0), + periodErrorCompensation(0.0), period(0.0), cntEdges(0), cntSmps(0), cntSmpsTotal(0), - horizonComp(10), - horizonEst(10), - filterWindow(horizonEst + 1, 0) + horizonCompensation(10), + horizonEstimation(10), + filterWindow(horizonEstimation + 1, 0) { } virtual void parse(json_t *json) @@ -87,9 +85,8 @@ public: Hook::parse(json); double fSmps = 0; - ret = json_unpack_ex(json, &err, 0, "{ s: i, s?: f, s: F}", - "signal_index", &idx, - "threshold", &thresh, + ret = json_unpack_ex(json, &err, 0, "{ s?: f, s: F }", + "threshold", &threshold, "expected_smp_rate", &fSmps ); if (ret) @@ -97,7 +94,7 @@ public: period = 1.0 / fSmps; - logger->debug("Parsed config thresh={} signal_index={} nominal_period={}", thresh, idx, period); + logger->debug("Parsed config threshold={} signal_index={} nominal_period={}", threshold, signalIndex, period); state = State::PARSED; } @@ -107,10 +104,10 @@ public: assert(state == State::STARTED); /* Get value of PPS signal */ - float value = smp->data[idx].f; // TODO check if it is really float + float value = smp->data[signalIndex].f; // TODO check if it is really float /* Detect Edge */ - bool isEdge = lastValue < thresh && value > thresh; + bool isEdge = lastValue < threshold && value > threshold; lastValue = value; @@ -123,12 +120,12 @@ public: filterWindow[cntEdges % filterWindow.size()] = cntSmpsTotal; - /* Estimated sample period over last 'horizonEst' seconds */ - unsigned int tmp = cntEdges < filterWindow.size() ? cntEdges : horizonEst; + /* Estimated sample period over last 'horizonEstimation' seconds */ + unsigned int tmp = cntEdges < filterWindow.size() ? cntEdges : horizonEstimation; double cntSmpsAvg = (cntSmpsTotal - filterWindow[(cntEdges - tmp) % filterWindow.size()]) / tmp; - periodEst = 1.0 / cntSmpsAvg; - periodErrComp = timeError / (cntSmpsAvg * horizonComp); - period = periodEst + periodErrComp; + periodEstimate = 1.0 / cntSmpsAvg; + periodErrorCompensation = timeError / (cntSmpsAvg * horizonCompensation); + period = periodEstimate + periodErrorCompensation; } else { tsVirt.tv_sec = time(nullptr); @@ -140,7 +137,7 @@ public: cntSmps = 0; cntEdges++; - logger->debug("Time Error is: {} periodEst {} periodErrComp {}", timeError, periodEst, periodErrComp); + logger->debug("Time Error is: {} periodEstimate {} periodErrorCompensation {}", timeError, periodEstimate, periodErrorCompensation); } cntSmps++; diff --git a/lib/hooks/scale.cpp b/lib/hooks/scale.cpp index abc5f7485..990d8149b 100644 --- a/lib/hooks/scale.cpp +++ b/lib/hooks/scale.cpp @@ -32,102 +32,62 @@ namespace villas { namespace node { -class ScaleHook : public Hook { +class ScaleHook : public MultiSignalHook { protected: - char *signal_name; - unsigned signal_index; - double scale; double offset; public: ScaleHook(struct vpath *p, struct vnode *n, int fl, int prio, bool en = true) : - Hook(p, n, fl, prio, en), - signal_name(nullptr), - signal_index(0), - scale(1), - offset(0) + MultiSignalHook(p, n, fl, prio, en), + scale(1.0), + offset(0.0) { } - virtual void prepare() - { - assert(state != State::STARTED); - - if (signal_name) { - signal_index = vlist_lookup_index(&signals, signal_name); - if (signal_index < 0) - throw RuntimeError("Failed to find signal: {}", signal_name); - } - - state = State::PREPARED; - } - - virtual ~ScaleHook() - { - if (signal_name) - free(signal_name); - } - virtual void parse(json_t *json) { int ret; - json_t *json_signal; json_error_t err; assert(state != State::STARTED); - Hook::parse(json); + MultiSignalHook::parse(json); - ret = json_unpack_ex(json, &err, 0, "{ s?: F, s?: F, s: o }", + ret = json_unpack_ex(json, &err, 0, "{ s?: F, s?: F }", "scale", &scale, - "offset", &offset, - "signal", &json_signal + "offset", &offset ); if (ret) throw ConfigError(json, err, "node-config-hook-scale"); - switch (json_typeof(json_signal)) { - case JSON_STRING: - signal_name = strdup(json_string_value(json_signal)); - break; - - case JSON_INTEGER: - signal_name = nullptr; - signal_index = json_integer_value(json_signal); - break; - - default: - throw ConfigError(json_signal, "node-config-hook-scale-signal", "Invalid value for setting 'signal'"); - } - state = State::PARSED; } virtual Hook::Reason process(struct sample *smp) { - unsigned k = signal_index; + for (auto index : signalIndices) { + assert(index < smp->length); + assert(state == State::STARTED); - assert(k < smp->length); - assert(state == State::STARTED); + switch (sample_format(smp, index)) { + case SignalType::INTEGER: + smp->data[index].i *= scale; + smp->data[index].i += offset; + break; - switch (sample_format(smp, k)) { - case SignalType::INTEGER: - smp->data[k].i *= scale; - smp->data[k].i += offset; - break; + case SignalType::FLOAT: + smp->data[index].f *= scale; + smp->data[index].f += offset; + break; - case SignalType::FLOAT: - smp->data[k].f *= scale; - smp->data[k].f += offset; - break; + case SignalType::COMPLEX: + smp->data[index].z *= scale; + smp->data[index].z += offset; + break; - case SignalType::COMPLEX: - smp->data[k].z *= scale; - smp->data[k].z += offset; - break; - - default: { } + default: { } + } } return Reason::OK;