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

added new format subsystem

This commit is contained in:
Steffen Vogel 2017-07-28 18:11:52 +02:00
parent d2300e7397
commit bc83463831
24 changed files with 591 additions and 179 deletions

View file

@ -47,6 +47,7 @@ typedef struct advio AFILE;
/* The remaining functions from stdio are just replaced macros */
#define afeof(af) feof((af)->file)
#define afgets(ln, sz, af) fgets(ln, sz, (af)->file)
#define aftell(af) ftell((af)->file)
#define afileno(af) fileno((af)->file)
#define afread(ptr, sz, nitems, af) fread(ptr, sz, nitems, (af)->file)

View file

@ -0,0 +1,35 @@
/** Comma-separated values.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#include "advio.h"
/* Forward declarations. */
struct sample;
#define CSV_SEPARATOR '\t'
int io_format_csv_fprint(AFILE *f, struct sample *smp, int flags);
int io_format_csv_fscan(AFILE *f, struct sample *smp, int *flags);

View file

@ -26,10 +26,10 @@
#include "sample.h"
int sample_io_json_pack(json_t **j, struct sample *s, int flags);
int io_format_json_pack(json_t **j, struct sample *s, int flags);
int sample_io_json_unpack(json_t *j, struct sample *s, int *flags);
int io_format_json_unpack(json_t *j, struct sample *s, int *flags);
int sample_io_json_fprint(FILE *f, struct sample *s, int flags);
int io_format_json_fprint(AFILE *f, struct sample *s, int flags);
int sample_io_json_fscan(FILE *f, struct sample *s, int *flags);
int io_format_json_fscan(AFILE *f, struct sample *s, int *flags);

View file

@ -0,0 +1,36 @@
/** The VILLASframework sample format
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#include <stdio.h>
/* VILLASnode human readable format */
int io_format_villas_print(char *buf, size_t len, struct sample *s, int flags);
int io_format_villas_scan(const char *line, struct sample *s, int *fl);
int io_format_villas_fprint(FILE *f, struct sample *s, int flags);
int io_format_villas_fscan(FILE *f, struct sample *s, int *flags);

81
include/villas/io.h Normal file
View file

@ -0,0 +1,81 @@
/** Read / write sample data in different formats.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#include "advio.h"
/* Forward declarations */
struct sample;
struct io;
/** These flags define the format which is used by io_fscan() and io_fprint(). */
enum io_flags {
IO_FORMAT_NANOSECONDS = (1 << 0),
IO_FORMAT_OFFSET = (1 << 1),
IO_FORMAT_SEQUENCE = (1 << 2),
IO_FORMAT_VALUES = (1 << 3),
IO_FORMAT_ALL = 16-1
};
struct io_format {
int (*init)(struct io *io);
int (*destroy)(struct io *io);
int (*open)(struct io *io, const char *uri, const char *mode);
int (*close)(struct io *io);
int (*eof)(struct io *io);
void (*rewind)(struct io *io);
int (*print)(struct io *io, struct sample *s, int fl);
int (*scan)(struct io *io, struct sample *s, int *fl);
size_t size; /**< Number of bytes to allocate for io::_vd */
};
struct io {
int flags;
/** A format type can use this file handle or overwrite the
* io_format::{open,close,eof,rewind} functions and the private
* data in io::_vd.
*/
AFILE *file;
void *_vd;
struct io_format *_vt;
};
int io_init(struct io *io, struct io_format *fmt, int flags);
int io_destroy(struct io *io);
int io_open(struct io *io, const char *uri, const char *mode);
int io_close(struct io *io);
int io_print(struct io *io, struct sample *smps[], size_t cnt);
int io_scan(struct io *io, struct sample *smps[], size_t cnt);
int io_eof(struct io *io);
void io_rewind(struct io *io);

View file

@ -23,6 +23,7 @@
#pragma once
#include "io.h"
#include "hook.h"
#include "api.h"
#include "common.h"
@ -53,6 +54,7 @@ enum plugin_type {
PLUGIN_TYPE_HOOK,
PLUGIN_TYPE_NODE,
PLUGIN_TYPE_API,
PLUGIN_TYPE_FORMAT,
PLUGIN_TYPE_FPGA_IP,
PLUGIN_TYPE_MODEL_CBUILDER
};
@ -71,6 +73,7 @@ struct plugin {
int (*unload)(struct plugin *p);
union {
struct io_format io;
struct api_action api;
struct node_type node;
#ifdef WITH_FPGA

View file

@ -1,89 +0,0 @@
/** Read / write sample data in different formats.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#include <stdio.h>
#include <jansson.h>
/* Forward declarations */
struct sample;
enum sample_io_format {
SAMPLE_IO_FORMAT_VILLAS,
SAMPLE_IO_FORMAT_JSON,
SAMPLE_IO_FORMAT_HDF5,
SAMPLE_IO_FORMAT_COMTRADE
};
/** These flags define the format which is used by sample_io_fscan() and sample_io_fprint(). */
enum sample_flags {
SAMPLE_IO_NANOSECONDS = (1 << 0),
SAMPLE_IO_OFFSET = (1 << 1),
SAMPLE_IO_SEQUENCE = (1 << 2),
SAMPLE_IO_VALUES = (1 << 3),
SAMPLE_IO_ALL = 16-1
};
/* Not implemented yet */
#if 0
struct sample_io_handle {
enum sample_io_format format;
int flags
FILE *file;
struct list fields;
};
int sample_io_init(struct sample_io *io, enum sample_io_format fmt, char *mode, int flags);
int sample_io_destroy(struct sample_io *io);
int sample_io_open(struct sample_io *io);
int sample_io_close(struct sample_io *io);
int sample_io_write(struct sample_io *io, struct sample *smps[], size_t cnt);
int sample_io_read(struct sample_io *io, struct sample *smps[], size_t cnt);
int sample_io_eof(struct sample_io *io);
int sample_io_rewind(struct sample_io *io);
#endif
/* Lowlevel interface */
int sample_io_fprint(FILE *f, struct sample *s, enum sample_io_format fmt, int flags);
int sample_io_fscan(FILE *f, struct sample *s, enum sample_io_format fmt, int *flags);
/* VILLASnode human readable format */
int sample_io_villas_print(char *buf, size_t len, struct sample *s, int flags);
int sample_io_villas_scan(const char *line, struct sample *s, int *fl);
int sample_io_villas_fprint(FILE *f, struct sample *s, int flags);
int sample_io_villas_fscan(FILE *f, struct sample *s, int *flags);

View file

@ -61,6 +61,8 @@ struct stats {
struct stats_delta *delta;
};
int stats_lookup_format(const char *str);
int stats_init(struct stats *s, int buckets, int warmup);
int stats_destroy(struct stats *s);

View file

@ -28,6 +28,7 @@ LIB_CFLAGS = $(CFLAGS) -fPIC
-include lib/hooks/Makefile.inc
-include lib/nodes/Makefile.inc
-include lib/formats/Makefile.inc
-include $(patsubst %, lib/Makefile.%.inc, $(SONAMES))

View file

@ -33,8 +33,8 @@ LIB_SRCS += $(addprefix lib/kernel/, kernel.c rt.c) \
$(addprefix lib/, sample.c path.c node.c hook.c log.c log_config.c \
utils.c super_node.c hist.c timing.c pool.c list.c queue.c \
queue_signalled.c memory.c advio.c plugin.c node_type.c stats.c \
mapping.c sample_io.c shmem.c config_helper.c crypt.c compat.c \
log_table.c log_helper.c
mapping.c io.c shmem.c config_helper.c crypt.c compat.c \
log_table.c log_helper.c \
)
LIB_LDFLAGS = -shared
@ -47,7 +47,7 @@ endif
LIB_PKGS += openssl libcurl
ifeq ($(WITH_JSON),1)
LIB_SRCS += lib/sample_io_json.c
LIB_SRCS += lib/formats/json.c
LIB_PKGS += jansson
LIB_CFLAGS += -DWITH_JSON
endif

23
lib/formats/Makefile.inc Normal file
View file

@ -0,0 +1,23 @@
# Makefile.
#
# @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
# @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
# @license GNU General Public License (version 3)
#
# VILLASnode
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
###################################################################################
LIB_SRCS += $(addprefix lib/formats/,villas.c csv.c msg.c webmsg.c)

105
lib/formats/csv.c Normal file
View file

@ -0,0 +1,105 @@
/** Comma-separated values.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <ctype.h>
#include "formats/csv.h"
#include "plugin.h"
#include "sample.h"
int io_format_csv_fprint(AFILE *f, struct sample *s, int flags)
{
afprintf(f, "%ld %09ld %d", s->ts.origin.tv_sec, s->ts.origin.tv_nsec, s->sequence);
for (int i = 0; i < s->length; i++) {
switch ((s->format >> i) & 0x1) {
case SAMPLE_DATA_FORMAT_FLOAT:
afprintf(f, "%c%.6f", CSV_SEPARATOR, s->data[i].f);
break;
case SAMPLE_DATA_FORMAT_INT:
afprintf(f, "%c%d", CSV_SEPARATOR, s->data[i].i);
break;
}
}
return 0;
}
int io_format_csv_fscan(AFILE *f, struct sample *smp, int *flags)
{
int ret, off;
char *ptr, line[4096];
skip: if (afgets(line, sizeof(line), f) == NULL)
return -1; /* An error occured */
/* Skip whitespaces, empty and comment lines */
for (ptr = line; isspace(*ptr); ptr++);
if (*ptr == '\0' || *ptr == '#')
goto skip;
ret = sscanf(line, "%ld %09ld %d %n", &smp->ts.origin.tv_sec, &smp->ts.origin.tv_nsec, &smp->sequence, &off);
if (ret != 4)
return -1;
int i;
for (i = 0; i < smp->capacity; i++) {
switch (smp->format & (1 << i)) {
case SAMPLE_DATA_FORMAT_FLOAT:
ret = sscanf(line + off, "%f %n", &smp->data[i].f, &off);
break;
case SAMPLE_DATA_FORMAT_INT:
ret = sscanf(line + off, "%d %n", &smp->data[i].i, &off);
break;
}
if (ret != 2)
break;
}
smp->length = i;
return ret;
}
int io_format_csv_print(struct io *io, struct sample *smp, int flags)
{
return io_format_csv_fprint(io->file, smp, flags);
}
int io_format_csv_scan(struct io *io, struct sample *smp, int *flags)
{
return io_format_csv_fscan(io->file, smp, flags);
}
static struct plugin p = {
.name = "csv",
.description = "Tabulator-separated values",
.type = PLUGIN_TYPE_FORMAT,
.io = {
.scan = io_format_csv_scan,
.print = io_format_csv_print,
.size = 0
}
};
REGISTER_PLUGIN(&p);

90
lib/formats/hdf5.c Normal file
View file

@ -0,0 +1,90 @@
#include "hdf5_hl.h"
#include <stdlib.h>
/*-------------------------------------------------------------------------
* Packet Table Fixed-Length Example
*
* Example program that creates a packet table and performs
* writes and reads.
*
*-------------------------------------------------------------------------
*/
int main(void)
{
hid_t fid; /* File identifier */
hid_t ptable; /* Packet table identifier */
herr_t err; /* Function return status */
hsize_t count; /* Number of records in the table */
int x; /* Loop variable */
/* Buffers to hold data */
int writeBuffer[5];
int readBuffer[5];
/* Initialize buffers */
for(x=0; x<5; x++)
{
writeBuffer[x]=x;
readBuffer[x] = -1;
}
/* Create a file using default properties */
fid=H5Fcreate("packet_table_FLexample.h5",H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT);
/* Create a fixed-length packet table within the file */
/* This table's "packets" will be simple integers. */
ptable = H5PTcreate_fl(fid, "Packet Test Dataset", H5T_NATIVE_INT, 1, 1);
if(ptable == H5I_INVALID_HID)
goto out;
/* Write one packet to the packet table */
err = H5PTappend(ptable, 1, &(writeBuffer[0]) );
if(err < 0)
goto out;
/* Write several packets to the packet table */
err = H5PTappend(ptable, 4, &(writeBuffer[1]) );
if(err < 0)
goto out;
/* Get the number of packets in the packet table. This should be five. */
err = H5PTget_num_packets(ptable, &count);
if(err < 0)
goto out;
printf("Number of packets in packet table after five appends: %llu\n", count);
/* Initialize packet table's "current record" */
err = H5PTcreate_index(ptable);
if(err < 0)
goto out;
/* Iterate through packets, read each one back */
for(x=0; x<5; x++)
{
err = H5PTget_next(ptable, 1, &(readBuffer[x]) );
if(err < 0)
goto out;
printf("Packet %d's value is %d\n", x, readBuffer[x]);
}
/* Close the packet table */
err = H5PTclose(ptable);
if(err < 0)
goto out;
/* Close the file */
H5Fclose(fid);
return 0;
out: /* An error has occurred. Clean up and exit. */
H5PTclose(ptable);
H5Fclose(fid);
return -1;
}

View file

@ -1,4 +1,4 @@
/** JSON serializtion sample data.
/** JSON serializtion of sample data.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
@ -20,9 +20,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include "sample_io_json.h"
#include "plugin.h"
#include "formats/json.h"
int sample_io_json_pack(json_t **j, struct sample *s, int flags)
int io_format_json_pack(json_t **j, struct sample *s, int flags)
{
json_error_t err;
json_t *json_data = json_array();
@ -49,7 +50,7 @@ int sample_io_json_pack(json_t **j, struct sample *s, int flags)
return 0;
}
int sample_io_json_unpack(json_t *j, struct sample *s, int *flags)
int io_format_json_unpack(json_t *j, struct sample *s, int *flags)
{
int ret, i;
json_t *json_data, *json_value;
@ -89,35 +90,58 @@ int sample_io_json_unpack(json_t *j, struct sample *s, int *flags)
return 0;
}
int sample_io_json_fprint(FILE *f, struct sample *s, int flags)
int io_format_json_fprint(AFILE *f, struct sample *s, int flags)
{
int ret;
json_t *json;
ret = sample_io_json_pack(&json, s, flags);
ret = io_format_json_pack(&json, s, flags);
if (ret)
return ret;
ret = json_dumpf(json, f, 0);
ret = json_dumpf(json, f->file, 0);
json_decref(json);
return ret;
}
int sample_io_json_fscan(FILE *f, struct sample *s, int *flags)
int io_format_json_fscan(AFILE *f, struct sample *s, int *flags)
{
int ret;
json_t *json;
json_error_t err;
json = json_loadf(f, JSON_DISABLE_EOF_CHECK, &err);
json = json_loadf(f->file, JSON_DISABLE_EOF_CHECK, &err);
if (!json)
return -1;
ret = sample_io_json_unpack(json, s, flags);
ret = io_format_json_unpack(json, s, flags);
json_decref(json);
return ret;
}
int io_format_json_print(struct io *io, struct sample *smp, int flags)
{
return io_format_json_fprint(io->file, smp, flags);
}
int io_format_json_scan(struct io *io, struct sample *smp, int *flags)
{
return io_format_json_fscan(io->file, smp, flags);
}
static struct plugin p = {
.name = "json",
.description = "Javascript Object Notation",
.type = PLUGIN_TYPE_FORMAT,
.io = {
.print = io_format_json_print,
.scan = io_format_json_scan,
.size = 0
},
};
REGISTER_PLUGIN(&p);

View file

@ -21,53 +21,28 @@
*********************************************************************************/
#include <ctype.h>
#include <string.h>
#include "io.h"
#include "plugin.h"
#include "utils.h"
#include "timing.h"
#include "sample.h"
#include "sample_io.h"
#ifdef WITH_JSON
#include "sample_io_json.h"
#endif
int sample_io_fprint(FILE *f, struct sample *s, enum sample_io_format fmt, int flags)
{
switch (fmt) {
case SAMPLE_IO_FORMAT_VILLAS: return sample_io_villas_fprint(f, s, flags);
#ifdef WITH_JSON
case SAMPLE_IO_FORMAT_JSON: return sample_io_json_fprint(f, s, flags);
#endif
default:
return -1;
}
}
int sample_io_fscan(FILE *f, struct sample *s, enum sample_io_format fmt, int *flags)
{
switch (fmt) {
case SAMPLE_IO_FORMAT_VILLAS: return sample_io_villas_fscan(f, s, flags);
#ifdef WITH_JSON
case SAMPLE_IO_FORMAT_JSON: return sample_io_json_fscan(f, s, flags);
#endif
default:
return -1;
}
}
int sample_io_villas_print(char *buf, size_t len, struct sample *s, int flags)
int io_format_villas_print(char *buf, size_t len, struct sample *s, int flags)
{
size_t off = snprintf(buf, len, "%llu", (unsigned long long) s->ts.origin.tv_sec);
if (flags & SAMPLE_IO_NANOSECONDS)
if (flags & IO_FORMAT_NANOSECONDS)
off += snprintf(buf + off, len - off, ".%09llu", (unsigned long long) s->ts.origin.tv_nsec);
if (flags & SAMPLE_IO_OFFSET)
if (flags & IO_FORMAT_OFFSET)
off += snprintf(buf + off, len - off, "%+e", time_delta(&s->ts.origin, &s->ts.received));
if (flags & SAMPLE_IO_SEQUENCE)
if (flags & IO_FORMAT_SEQUENCE)
off += snprintf(buf + off, len - off, "(%u)", s->sequence);
if (flags & SAMPLE_IO_VALUES) {
if (flags & IO_FORMAT_VALUES) {
for (int i = 0; i < s->length; i++) {
switch ((s->format >> i) & 0x1) {
case SAMPLE_DATA_FORMAT_FLOAT:
@ -85,7 +60,7 @@ int sample_io_villas_print(char *buf, size_t len, struct sample *s, int flags)
return 0; /* trailing '\0' */
}
int sample_io_villas_scan(const char *line, struct sample *s, int *fl)
int io_format_villas_scan(const char *line, struct sample *s, int *fl)
{
char *end;
const char *ptr = line;
@ -110,7 +85,7 @@ int sample_io_villas_scan(const char *line, struct sample *s, int *fl)
s->ts.origin.tv_nsec = (uint32_t) strtoul(ptr, &end, 10);
if (ptr != end)
flags |= SAMPLE_IO_NANOSECONDS;
flags |= IO_FORMAT_NANOSECONDS;
else
return -3;
}
@ -123,7 +98,7 @@ int sample_io_villas_scan(const char *line, struct sample *s, int *fl)
offset = strtof(ptr, &end); /* offset is ignored for now */
if (ptr != end)
flags |= SAMPLE_IO_OFFSET;
flags |= IO_FORMAT_OFFSET;
else
return -4;
}
@ -134,7 +109,7 @@ int sample_io_villas_scan(const char *line, struct sample *s, int *fl)
s->sequence = strtoul(ptr, &end, 10);
if (ptr != end)
flags |= SAMPLE_IO_SEQUENCE;
flags |= IO_FORMAT_SEQUENCE;
else
return -5;
@ -160,11 +135,11 @@ int sample_io_villas_scan(const char *line, struct sample *s, int *fl)
}
if (s->length > 0)
flags |= SAMPLE_IO_VALUES;
flags |= IO_FORMAT_VALUES;
if (fl)
*fl = flags;
if (flags & SAMPLE_IO_OFFSET) {
if (flags & IO_FORMAT_OFFSET) {
struct timespec off = time_from_double(offset);
s->ts.received = time_add(&s->ts.origin, &off);
}
@ -174,12 +149,12 @@ int sample_io_villas_scan(const char *line, struct sample *s, int *fl)
return 0;
}
int sample_io_villas_fprint(FILE *f, struct sample *s, int flags)
int io_format_villas_fprint(FILE *f, struct sample *s, int flags)
{
char line[4096];
int ret;
ret = sample_io_villas_print(line, sizeof(line), s, flags);
ret = io_format_villas_print(line, sizeof(line), s, flags);
if (ret)
return ret;
@ -188,7 +163,7 @@ int sample_io_villas_fprint(FILE *f, struct sample *s, int flags)
return 0;
}
int sample_io_villas_fscan(FILE *f, struct sample *s, int *fl)
int io_format_villas_fscan(FILE *f, struct sample *s, int *fl)
{
char *ptr, line[4096];
@ -200,5 +175,18 @@ skip: if (fgets(line, sizeof(line), f) == NULL)
if (*ptr == '\0' || *ptr == '#')
goto skip;
return sample_io_villas_scan(line, s, fl);
return io_format_villas_scan(line, s, fl);
}
struct plugin p = {
.name = "villas",
.description = "Human readable VILLAS format",
.type = PLUGIN_TYPE_FORMAT,
.io = {
.fprint = io_format_villas_fprint,
.fscan = io_format_villas_fscan,
.size = 0
}
};
REGISTER_PLUGIN(&p);

View file

@ -27,10 +27,10 @@
#include "hook.h"
#include "plugin.h"
#include "sample.h"
#include "sample_io.h"
#include "io.h"
struct print {
FILE *output;
struct io output;
const char *uri;
};
@ -38,7 +38,6 @@ static int print_init(struct hook *h)
{
struct print *p = h->_vd;
p->output = stdout;
p->uri = NULL;
return 0;
@ -48,23 +47,14 @@ static int print_start(struct hook *h)
{
struct print *p = h->_vd;
if (p->uri) {
p->output = fopen(p->uri, "w+");
if (!p->output)
error("Failed to open file %s for writing", p->uri);
}
return 0;
return io_open(&p->output, p->uri, "w+");
}
static int print_stop(struct hook *h)
{
struct print *p = h->_vd;
if (p->uri)
fclose(p->output);
return 0;
return io_close(&p->output);
}
static int print_parse(struct hook *h, config_setting_t *cfg)
@ -80,8 +70,7 @@ static int print_read(struct hook *h, struct sample *smps[], size_t *cnt)
{
struct print *p = h->_vd;
for (int i = 0; i < *cnt; i++)
sample_io_villas_fprint(p->output, smps[i], SAMPLE_IO_ALL);
io_print(&p->output, smps, *cnt);
return 0;
}

View file

@ -119,14 +119,13 @@ static int stats_collect_parse(struct hook *h, config_setting_t *cfg)
const char *format;
if (config_setting_lookup_string(cfg, "format", &format)) {
if (!strcmp(format, "human"))
p->format = STATS_FORMAT_HUMAN;
else if (!strcmp(format, "json"))
p->format = STATS_FORMAT_JSON;
else if (!strcmp(format, "matlab"))
p->format = STATS_FORMAT_MATLAB;
else
int fmt;
fmt = stats_lookup_format(format);
if (fmt < 0)
cerror(cfg, "Invalid statistic output format: %s", format);
p->format = fmt;
}
config_setting_lookup_bool(cfg, "verbose", &p->verbose);

102
lib/io.c Normal file
View file

@ -0,0 +1,102 @@
/** Reading and writing simulation samples in various formats.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <stdlib.h>
#include "io.h"
#include "utils.h"
int io_init(struct io *io, struct io_format *fmt, int flags)
{
io->_vt = fmt;
io->_vd = alloc(fmt->size);
io->flags = flags;
return io->_vt->init ? io->_vt->init(io) : 0;
}
int io_destroy(struct io *io)
{
int ret;
ret = io->_vt->destroy ? io->_vt->destroy(io) : 0;
if (ret)
return ret;
free(io->_vd);
return 0;
}
int io_open(struct io *io, const char *uri, const char *mode)
{
if (io->_vt->open)
return io->_vt->open(io, uri, mode);
else {
io->file = afopen(uri, mode);
if (!io->file)
return -1;
return 0;
}
}
int io_close(struct io *io)
{
return io->_vt->close ? io->_vt->close(io) : afclose(io->file);
}
int io_print(struct io *io, struct sample *smps[], size_t cnt)
{
assert(io->_vt->print);
for (int i = 0; i < cnt; i++)
io->_vt->print(io, smps[i], io->flags);
return cnt;
}
int io_scan(struct io *io, struct sample *smps[], size_t cnt)
{
int ret;
assert(io->_vt->scan);
for (int i = 0; i < cnt && !io_eof(io); i++) {
ret = io->_vt->scan(io, smps[i], NULL);
if (ret < 0)
return i;
}
return cnt;
}
int io_eof(struct io *io)
{
return io->_vt->eof ? io->_vt->eof(io) : afeof(io->file);
}
void io_rewind(struct io *io)
{
io->_vt->rewind ? io->_vt->rewind(io) : arewind(io->file);
}

View file

@ -27,6 +27,7 @@ ifeq ($(PLATFORM),Linux)
WITH_SIGNAL ?= 1
WITH_NGSI ?= 1
WITH_FPGA ?= 1
WITH_TEST_RTT ?= 1
endif
WITH_WEBSOCKET ?= 1
@ -53,6 +54,12 @@ ifeq ($(WITH_SIGNAL),1)
LIB_CFLAGS += -DWITH_SIGNAL
endif
# Enable RTT test node-tyoe
ifeq ($(WITH_TEST_RTT),1)
LIB_SRCS += lib/nodes/test_rtt.c
LIB_CFLAGS += -DWITH_TEST_RTT
endif
# Enable VILLASfpga support when libxil is available
ifeq ($(WITH_FPGA),1)
ifeq ($(shell $(PKGCONFIG) libxil; echo $$?),0)

View file

@ -29,7 +29,7 @@
#include "timing.h"
#include "queue.h"
#include "plugin.h"
#include "sample_io.h"
#include "formats/villas.h"
int file_reverse(struct node *n)
{
@ -264,7 +264,7 @@ int file_start(struct node *n)
struct sample s;
s.capacity = 0;
ret = sample_io_villas_fscan(f->read.handle->file, &s, NULL);
ret = io_format_villas_fscan(f->read.handle->file, &s, NULL);
if (ret < 0)
error("Failed to read first timestamp of node %s", node_name(n));
@ -314,7 +314,7 @@ int file_read(struct node *n, struct sample *smps[], unsigned cnt)
assert(f->read.handle);
assert(cnt == 1);
retry: values = sample_io_villas_fscan(f->read.handle->file, s, &flags); /* Get message and timestamp */
retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get message and timestamp */
if (values < 0) {
if (afeof(f->read.handle)) {
switch (f->read_eof) {
@ -373,7 +373,7 @@ int file_write(struct node *n, struct sample *smps[], unsigned cnt)
assert(f->write.handle);
assert(cnt == 1);
sample_io_villas_fprint(f->write.handle->file, s, SAMPLE_IO_ALL & ~SAMPLE_IO_OFFSET);
io_format_villas_fprint(f->write.handle->file, s, IO_FORMAT_ALL & ~IO_FORMAT_OFFSET);
if (f->flush)
afflush(f->write.handle);

View file

@ -44,6 +44,18 @@ static struct stats_desc {
{ "owd", "seconds", "Histogram for one-way-delay (OWD) of received messages", 25 }
};
int stats_lookup_format(const char *str)
{
if (!strcmp(str, "human"))
return STATS_FORMAT_HUMAN;
else if (!strcmp(str, "json"))
return STATS_FORMAT_JSON;
else if (!strcmp(str, "matlab"))
return STATS_FORMAT_MATLAB;
else
return -1;
}
int stats_init(struct stats *s, int buckets, int warmup)
{
for (int i = 0; i < STATS_COUNT; i++)

View file

@ -36,7 +36,7 @@
#include <villas/msg.h>
#include <villas/timing.h>
#include <villas/pool.h>
#include <villas/sample_io.h>
#include <villas/io.h>
#include <villas/kernel/rt.h>
#include <villas/nodes/websocket.h>
@ -84,6 +84,7 @@ static void usage()
printf(" CONFIG path to a configuration file\n");
printf(" NODE the name of the node to which samples are sent and received from\n");
printf(" OPTIONS are:\n");
printf(" -f FMT set the format\n")
printf(" -d LVL set debug log level to LVL\n");
printf(" -x swap read / write endpoints\n");
printf(" -s only read data from stdin and send it to node\n");
@ -207,8 +208,10 @@ int main(int argc, char *argv[])
};
char c, *endptr;
while ((c = getopt(argc, argv, "hxrsd:l:L:t:")) != -1) {
while ((c = getopt(argc, argv, "hxrsd:l:L:t:f:")) != -1) {
switch (c) {
case 'f';
case 'x':
reverse = true;
break;