1
0
Fork 0
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:
Steffen Vogel 2018-08-13 15:31:39 +02:00
parent e4ba1a3d48
commit d0cecc3c91
3 changed files with 471 additions and 58 deletions

View file

@ -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

View file

@ -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
}

View file

@ -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;
}
}