mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
signal: added more and more functionality
This commit is contained in:
parent
e4ba1a3d48
commit
d0cecc3c91
3 changed files with 471 additions and 58 deletions
|
@ -26,16 +26,8 @@
|
|||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <complex.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
/* "I" defined by complex.h collides with a define in OpenSSL */
|
||||
#undef I
|
||||
#define J _Complex_I
|
||||
|
||||
|
||||
#include <villas/atomic.h>
|
||||
#include <villas/signal.h>
|
||||
|
||||
|
@ -87,13 +79,17 @@ struct sample {
|
|||
struct timespec received; /**< The point in time when this data was received. */
|
||||
} ts;
|
||||
|
||||
/** The values. */
|
||||
union {
|
||||
double f; /**< Floating point values. */
|
||||
int64_t i; /**< Integer values. */
|
||||
bool b; /**< Boolean values. */
|
||||
float _Complex z; /**< Complex values. */
|
||||
} data[]; /**< Data is in host endianess! */
|
||||
/** The sample signal values.
|
||||
*
|
||||
* This variable length array (VLA) extends over the end of struct sample.
|
||||
* Make sure that pointers to struct sample point to memory blocks of adequate size.
|
||||
* Use the SAMPLE_LENGTH() macro to calculate the required size.
|
||||
*
|
||||
* Metadata describing the details of signal values (such as name, unit, data type and more)
|
||||
* are stored in the struct sample::signals list. Each entry in this list corresponedents
|
||||
* to an entry in the struct sample::data array.
|
||||
*/
|
||||
union signal_data data[];
|
||||
};
|
||||
|
||||
#define SAMPLE_NON_POOL PTRDIFF_MIN
|
||||
|
|
|
@ -24,6 +24,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <jansson.h>
|
||||
#include <complex.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* "I" defined by complex.h collides with a define in OpenSSL */
|
||||
#undef I
|
||||
|
||||
#include <villas/atomic.h>
|
||||
|
||||
|
@ -36,12 +42,24 @@ struct list;
|
|||
struct node;
|
||||
struct mapping_entry;
|
||||
|
||||
/** A signal value.
|
||||
*
|
||||
* Data is in host endianess!
|
||||
*/
|
||||
union signal_data {
|
||||
double f; /**< Floating point values. */
|
||||
int64_t i; /**< Integer values. */
|
||||
bool b; /**< Boolean values. */
|
||||
float _Complex z; /**< Complex values. */
|
||||
};
|
||||
|
||||
enum signal_format {
|
||||
SIGNAL_FORMAT_FLOAT = 0,
|
||||
SIGNAL_FORMAT_INT = 1,
|
||||
SIGNAL_FORMAT_BOOL = 2,
|
||||
SIGNAL_FORMAT_COMPLEX = 3,
|
||||
SIGNAL_FORMAT_UNKNOWN = -1
|
||||
SIGNAL_FORMAT_INVALID = 0, /**< Signal format is invalid. */
|
||||
SIGNAL_FORMAT_AUTO = 1, /**< Signal format is unknown. Try autodetection. */
|
||||
SIGNAL_FORMAT_FLOAT = 2, /**< See signal_data::f */
|
||||
SIGNAL_FORMAT_INT = 3, /**< See signal_data::i */
|
||||
SIGNAL_FORMAT_BOOL = 4, /**< See signal_data::b */
|
||||
SIGNAL_FORMAT_COMPLEX = 5 /**< See signal_data::z */
|
||||
};
|
||||
|
||||
/** Signal descriptor.
|
||||
|
@ -52,6 +70,8 @@ struct signal {
|
|||
char *name; /**< The name of the signal. */
|
||||
char *unit; /**< The unit of the signal. */
|
||||
|
||||
union signal_data init; /**< The initial value of the signal. */
|
||||
|
||||
int enabled;
|
||||
|
||||
atomic_int refcnt; /**< Reference counter. */
|
||||
|
@ -59,23 +79,53 @@ struct signal {
|
|||
enum signal_format format;
|
||||
};
|
||||
|
||||
/** Initialize a signal with default values. */
|
||||
int signal_init(struct signal *s);
|
||||
|
||||
/** Destroy a signal and release memory. */
|
||||
int signal_destroy(struct signal *s);
|
||||
|
||||
/** Allocate memory for a new signal, and initialize it with provided values. */
|
||||
struct signal * signal_create(const char *name, const char *unit, enum signal_format fmt);
|
||||
|
||||
/** Destroy and release memory of signal. */
|
||||
int signal_free(struct signal *s);
|
||||
|
||||
/** Increase reference counter. */
|
||||
int signal_incref(struct signal *s);
|
||||
|
||||
/** Decrease reference counter. */
|
||||
int signal_decref(struct signal *s);
|
||||
|
||||
int signal_init_from_mapping(struct signal *s, const struct mapping_entry *me, unsigned index);
|
||||
|
||||
int signal_destroy(struct signal *s);
|
||||
|
||||
/** Parse signal description. */
|
||||
int signal_parse(struct signal *s, json_t *cfg);
|
||||
|
||||
int signal_parse_list(struct list *list, json_t *cfg);
|
||||
/** Initialize signal from a mapping_entry. */
|
||||
int signal_init_from_mapping(struct signal *s, const struct mapping_entry *me, unsigned index);
|
||||
|
||||
int signal_get_offset(const char *str, struct node *n);
|
||||
int signal_list_parse(struct list *list, json_t *cfg);
|
||||
|
||||
int signal_list_generate(struct list *list, unsigned len, enum signal_format fmt);
|
||||
|
||||
void signal_list_dump(const struct list *list);
|
||||
|
||||
enum signal_format signal_format_from_str(const char *str);
|
||||
|
||||
const char * signal_format_to_str(enum signal_format fmt);
|
||||
|
||||
enum signal_format signal_format_detect(const char *val);
|
||||
|
||||
/** Convert signal data from one description/format to another. */
|
||||
void signal_data_convert(union signal_data *data, const struct signal *from, const struct signal *to);
|
||||
|
||||
/** Print value of a signal to a character buffer. */
|
||||
int signal_data_snprint(const union signal_data *data, const struct signal *sig, char *buf, size_t len);
|
||||
|
||||
int signal_data_parse_str(union signal_data *data, const struct signal *sig, const char *ptr, char **end);
|
||||
|
||||
int signal_data_parse_json(union signal_data *data, const struct signal *sig, json_t *cfg);
|
||||
|
||||
void signal_data_set(union signal_data *data, const struct signal *sig, double val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
431
lib/signal.c
431
lib/signal.c
|
@ -21,7 +21,7 @@
|
|||
*********************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <villas/signal.h>
|
||||
#include <villas/list.h>
|
||||
#include <villas/utils.h>
|
||||
|
@ -30,9 +30,11 @@
|
|||
|
||||
int signal_init(struct signal *s)
|
||||
{
|
||||
s->enabled = true;
|
||||
|
||||
s->name = NULL;
|
||||
s->unit = NULL;
|
||||
s->format = SIGNAL_FORMAT_UNKNOWN;
|
||||
s->format = SIGNAL_FORMAT_AUTO;
|
||||
|
||||
s->refcnt = ATOMIC_VAR_INIT(1);
|
||||
|
||||
|
@ -70,7 +72,7 @@ int signal_init_from_mapping(struct signal *s, const struct mapping_entry *me, u
|
|||
break;
|
||||
|
||||
case MAPPING_TYPE_HEADER:
|
||||
switch (me->hdr.type) {
|
||||
switch (me->header.type) {
|
||||
case MAPPING_HEADER_TYPE_LENGTH:
|
||||
case MAPPING_HEADER_TYPE_SEQUENCE:
|
||||
s->format = SIGNAL_FORMAT_INT;
|
||||
|
@ -83,8 +85,7 @@ int signal_init_from_mapping(struct signal *s, const struct mapping_entry *me, u
|
|||
break;
|
||||
|
||||
case MAPPING_TYPE_DATA:
|
||||
s->format = me->signal->format;
|
||||
s->unit = me->signal->unit;
|
||||
*s = *me->data.signal;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -96,6 +97,46 @@ int signal_destroy(struct signal *s)
|
|||
if (s->name)
|
||||
free(s->name);
|
||||
|
||||
if (s->unit)
|
||||
free(s->unit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct signal * signal_create(const char *name, const char *unit, enum signal_format fmt)
|
||||
{
|
||||
int ret;
|
||||
struct signal *sig;
|
||||
|
||||
sig = alloc(sizeof(struct signal));
|
||||
if (!sig)
|
||||
return NULL;
|
||||
|
||||
ret = signal_init(sig);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
if (name)
|
||||
sig->name = strdup(name);
|
||||
|
||||
if (unit)
|
||||
sig->unit = strdup(unit);
|
||||
|
||||
sig->format = fmt;
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
int signal_free(struct signal *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = signal_destroy(s);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
free(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -110,7 +151,7 @@ int signal_decref(struct signal *s)
|
|||
|
||||
/* Did we had the last reference? */
|
||||
if (prev == 1)
|
||||
signal_destroy(s);
|
||||
signal_free(s);
|
||||
|
||||
return prev - 1;
|
||||
}
|
||||
|
@ -119,29 +160,47 @@ int signal_parse(struct signal *s, json_t *cfg)
|
|||
{
|
||||
int ret;
|
||||
json_error_t err;
|
||||
const char *name;
|
||||
json_t *json_init = NULL;
|
||||
const char *name = NULL;
|
||||
const char *unit = NULL;
|
||||
const char *format = NULL;
|
||||
|
||||
/* Default values */
|
||||
s->enabled = true;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: s, s?: b }",
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: s, s?: s, s?: o, s?: b }",
|
||||
"name", &name,
|
||||
"unit", &unit,
|
||||
"format", &format,
|
||||
"init", &json_init,
|
||||
"enabled", &s->enabled
|
||||
);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
s->name = strdup(name);
|
||||
s->unit = unit
|
||||
? strdup(unit)
|
||||
: NULL;
|
||||
if (name)
|
||||
s->name = strdup(name);
|
||||
|
||||
if (unit)
|
||||
s->unit = strdup(unit);
|
||||
|
||||
if (format) {
|
||||
s->format = signal_format_from_str(format);
|
||||
if (s->format == SIGNAL_FORMAT_INVALID)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (json_init) {
|
||||
ret = signal_data_parse_json(&s->init, s, json_init);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
signal_data_set(&s->init, s, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int signal_parse_list(struct list *list, json_t *cfg)
|
||||
/* Signal list */
|
||||
|
||||
int signal_list_parse(struct list *list, json_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
struct signal *s;
|
||||
|
@ -156,9 +215,13 @@ int signal_parse_list(struct list *list, json_t *cfg)
|
|||
if (!s)
|
||||
return -1;
|
||||
|
||||
ret = signal_init(s);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = signal_parse(s, json_signal);
|
||||
if (ret)
|
||||
return -1;
|
||||
return ret;
|
||||
|
||||
list_push(list, s);
|
||||
}
|
||||
|
@ -166,23 +229,327 @@ int signal_parse_list(struct list *list, json_t *cfg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int signal_get_offsets(const char *str, struct list *sigs)
|
||||
int signal_list_generate(struct list *list, unsigned len, enum signal_format fmt)
|
||||
{
|
||||
int idx;
|
||||
char *endptr;
|
||||
struct signal *s;
|
||||
for (int i = 0; i < len; i++) {
|
||||
char name[32];
|
||||
snprintf(name, sizeof(name), "signal%d", i);
|
||||
|
||||
/* Lets try to find a signal with a matching name */
|
||||
if (1) {
|
||||
s = list_lookup(sigs, str);
|
||||
if (s)
|
||||
return list_index(sigs, s);
|
||||
struct signal *sig = signal_create(name, NULL, fmt);
|
||||
if (!sig)
|
||||
return -1;
|
||||
|
||||
list_push(list, sig);
|
||||
}
|
||||
|
||||
/* Lets try to interpret the signal name as an index */
|
||||
idx = strtoul(str, &endptr, 10);
|
||||
if (endptr == str + strlen(str))
|
||||
return idx;
|
||||
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void signal_list_dump(const struct list *list)
|
||||
{
|
||||
info ("Signals:");
|
||||
|
||||
for (int i = 0; i < list_length(list); i++) {
|
||||
struct signal *sig = list_at(list, i);
|
||||
|
||||
if (sig->unit)
|
||||
info(" %d: %s [%s] = %s", i, sig->name, sig->unit, signal_format_to_str(sig->format));
|
||||
else
|
||||
info(" %d: %s = %s", i, sig->name, signal_format_to_str(sig->format));
|
||||
}
|
||||
}
|
||||
|
||||
/* Signal format */
|
||||
|
||||
enum signal_format signal_format_from_str(const char *str)
|
||||
{
|
||||
if (!strcmp(str, "boolean"))
|
||||
return SIGNAL_FORMAT_BOOL;
|
||||
else if (!strcmp(str, "complex"))
|
||||
return SIGNAL_FORMAT_COMPLEX;
|
||||
else if (!strcmp(str, "float"))
|
||||
return SIGNAL_FORMAT_FLOAT;
|
||||
else if (!strcmp(str, "integer"))
|
||||
return SIGNAL_FORMAT_INT;
|
||||
else if (!strcmp(str, "auto"))
|
||||
return SIGNAL_FORMAT_AUTO;
|
||||
else
|
||||
return SIGNAL_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
const char * signal_format_to_str(enum signal_format fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
return "boolean";
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX:
|
||||
return "complex";
|
||||
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
return "float";
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
return "integer";
|
||||
|
||||
case SIGNAL_FORMAT_AUTO:
|
||||
return "auto";
|
||||
|
||||
case SIGNAL_FORMAT_INVALID:
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum signal_format signal_format_detect(const char *val)
|
||||
{
|
||||
char *brk;
|
||||
int len;
|
||||
|
||||
debug(LOG_IO | 5, "Attempt to detect format of: %s", val);
|
||||
|
||||
brk = strchr(val, 'i');
|
||||
if (brk)
|
||||
return SIGNAL_FORMAT_COMPLEX;
|
||||
|
||||
brk = strchr(val, '.');
|
||||
if (brk)
|
||||
return SIGNAL_FORMAT_FLOAT;
|
||||
|
||||
len = strlen(val);
|
||||
if (len == 1 && (val[0] == '1' || val[0] == '0'))
|
||||
return SIGNAL_FORMAT_BOOL;
|
||||
|
||||
return SIGNAL_FORMAT_INT;
|
||||
}
|
||||
|
||||
/* Signal data */
|
||||
|
||||
void signal_data_set(union signal_data *data, const struct signal *sig, double val)
|
||||
{
|
||||
switch (sig->format) {
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
data->b = val;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
data->f = val;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
data->i = val;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX:
|
||||
data->z = val;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_INVALID:
|
||||
case SIGNAL_FORMAT_AUTO:
|
||||
memset(data, 0, sizeof(union signal_data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void signal_data_convert(union signal_data *data, const struct signal *from, const struct signal *to)
|
||||
{
|
||||
if (from == to) /* Nothing to do */
|
||||
return;
|
||||
|
||||
switch (to->format) {
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
switch(from->format) {
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
data->b = data->b;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
data->b = data->i;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
data->b = data->f;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX:
|
||||
data->b = creal(data->z);
|
||||
break;
|
||||
|
||||
default: { }
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
switch(from->format) {
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
data->i = data->b;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
data->i = data->i;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
data->i = data->f;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX:
|
||||
data->i = creal(data->z);
|
||||
break;
|
||||
|
||||
default: { }
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
switch(from->format) {
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
data->f = data->b;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
data->f = data->i;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
data->f = data->f;
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX:
|
||||
data->f = creal(data->z);
|
||||
break;
|
||||
|
||||
default: { }
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX:
|
||||
switch(from->format) {
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
data->z = CMPLXF(data->b, 0);
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
data->z = CMPLXF(data->i, 0);
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
data->z = CMPLXF(data->f, 0);
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX:
|
||||
data->z = data->z;
|
||||
break;
|
||||
|
||||
default: { }
|
||||
}
|
||||
break;
|
||||
|
||||
default: { }
|
||||
}
|
||||
}
|
||||
|
||||
int signal_data_parse_str(union signal_data *data, const struct signal *sig, const char *ptr, char **end)
|
||||
{
|
||||
switch (sig->format) {
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
data->f = strtod(ptr, end);
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
data->i = strtol(ptr, end, 10);
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
data->b = strtol(ptr, end, 10);
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX: {
|
||||
float real, imag;
|
||||
|
||||
real = strtod(ptr, end);
|
||||
if (*end == ptr)
|
||||
return -1;
|
||||
|
||||
ptr = *end;
|
||||
|
||||
imag = strtod(ptr, end);
|
||||
if (*end == ptr)
|
||||
return -1;
|
||||
|
||||
if (**end != 'i')
|
||||
return -1;
|
||||
|
||||
(*end)++;
|
||||
|
||||
data->z = CMPLXF(real, imag);
|
||||
break;
|
||||
}
|
||||
|
||||
case SIGNAL_FORMAT_AUTO:
|
||||
case SIGNAL_FORMAT_INVALID:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int signal_data_parse_json(union signal_data *data, const struct signal *sig, json_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (sig->format) {
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
data->f = json_real_value(cfg);
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
data->i = json_integer_value(cfg);
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
data->b = json_boolean_value(cfg);
|
||||
break;
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX: {
|
||||
double real, imag;
|
||||
|
||||
ret = json_unpack(cfg, "{ s: F, s: F }",
|
||||
"real", &real,
|
||||
"imag", &imag
|
||||
);
|
||||
if (ret)
|
||||
return -2;
|
||||
|
||||
data->z = CMPLXF(real, imag);
|
||||
break;
|
||||
}
|
||||
|
||||
case SIGNAL_FORMAT_INVALID:
|
||||
case SIGNAL_FORMAT_AUTO:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int signal_data_snprint(const union signal_data *data, const struct signal *sig, char *buf, size_t len)
|
||||
{
|
||||
switch (sig->format) {
|
||||
case SIGNAL_FORMAT_FLOAT:
|
||||
return snprintf(buf, len, "%.6f", data->f);
|
||||
|
||||
case SIGNAL_FORMAT_INT:
|
||||
return snprintf(buf, len, "%" PRIi64, data->i);
|
||||
|
||||
case SIGNAL_FORMAT_BOOL:
|
||||
return snprintf(buf, len, "%u", data->b);
|
||||
|
||||
case SIGNAL_FORMAT_COMPLEX:
|
||||
return snprintf(buf, len, "%.6f%+.6fi", creal(data->z), cimag(data->z));
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue