1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

hook: adapt existing hooks to derive from {Multi,Single}SignalHook classes

This commit is contained in:
Steffen Vogel 2021-07-06 16:28:10 +02:00
parent 870e563568
commit d54fcdf5d8
6 changed files with 110 additions and 331 deletions

View file

@ -25,7 +25,6 @@
*/
#include <bitset>
#include <cstring>
#include <villas/hook.hpp>
@ -36,34 +35,16 @@
namespace villas {
namespace node {
class AverageHook : public Hook {
class AverageHook : public MultiSignalHook {
protected:
unsigned offset;
std::bitset<MAX_SAMPLE_LENGTH> 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<struct signal>(&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:

View file

@ -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<struct signal>(&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;
}

View file

@ -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<struct signal>(&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);

View file

@ -36,37 +36,20 @@
namespace villas {
namespace node {
class LimitValueHook : public Hook {
class LimitValueHook : public MultiSignalHook {
protected:
unsigned offset;
float min, max;
std::bitset<MAX_SAMPLE_LENGTH> 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<struct signal>(&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:

View file

@ -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<uintmax_t> 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++;

View file

@ -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<struct signal>(&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;