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

ported io/format code to C++

This commit is contained in:
Steffen Vogel 2021-05-10 00:12:30 +02:00
parent 5a95fc0bd6
commit 731909c3a8
168 changed files with 2436 additions and 2696 deletions

View file

@ -36,6 +36,7 @@ set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_THREAD_PREFER_PTHREAD ON)
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake;${PROJECT_SOURCE_DIR}/common/cmake")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(TOPLEVEL_PROJECT ON)

170
include/villas/format.hpp Normal file
View file

@ -0,0 +1,170 @@
/** Read / write sample data in different formats.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <villas/list.h>
#include <villas/plugin.hpp>
#include <villas/sample.h>
namespace villas {
namespace node {
class Format {
protected:
int flags; /**< A set of flags which is automatically used. */
int real_precision; /**< Number of digits used for floatint point numbers */
bool destroy_signals;
struct {
char *buffer;
size_t buflen;
} in, out;
struct vlist *signals; /**< Signal meta data for parsed samples by Format::scan() */
public:
Format(int fl);
virtual bool isBinaryPayload()
{ return false; }
struct vlist * getSignals() const
{ return signals; }
int getFlags() const
{ return flags; }
virtual ~Format();
void start(struct vlist *sigs, int fl = (int) SampleFlags::HAS_ALL);
void start(const std::string &dtypes, int fl = (int) SampleFlags::HAS_ALL);
virtual void start()
{ }
virtual void parse(json_t *json);
virtual int print(FILE *f, const struct sample * const smps[], unsigned cnt);
virtual int scan(FILE *f, struct sample * const smps[], unsigned cnt);
/** Print \p cnt samples from \p smps into buffer \p buf of length \p len.
*
* @param buf[out] The buffer which should be filled with serialized data.
* @param len[in] The length of the buffer \p buf.
* @param rbytes[out] The number of bytes which have been written to \p buf. Ignored if nullptr.
* @param smps[in] The array of pointers to samples.
* @param cnt[in] The number of pointers in the array \p smps.
*
* @retval >=0 The number of samples from \p smps which have been written into \p buf.
* @retval <0 Something went wrong.
*/
virtual int sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt) = 0;
/** Parse samples from the buffer \p buf with a length of \p len bytes.
*
* @param buf[in] The buffer of data which should be parsed / de-serialized.
* @param len[in] The length of the buffer \p buf.
* @param rbytes[out] The number of bytes which have been read from \p buf.
* @param smps[out] The array of pointers to samples.
* @param cnt[in] The number of pointers in the array \p smps.
*
* @retval >=0 The number of samples which have been parsed from \p buf and written into \p smps.
* @retval <0 Something went wrong.
*/
virtual int sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt) = 0;
/* Wrappers for sending a (un)parsing single samples */
int print(FILE *f, const struct sample *smp)
{
return print(f, &smp, 1);
}
int scan(FILE *f, struct sample *smp)
{
return scan(f, &smp, 1);
}
int sprint(char *buf, size_t len, size_t *wbytes, const struct sample *smp)
{
return sprint(buf, len, wbytes, &smp, 1);
}
int sscan(const char *buf, size_t len, size_t *rbytes, struct sample *smp)
{
return sscan(buf, len, rbytes, &smp, 1);
}
};
class BinaryFormat : public Format {
public:
using Format::Format;
virtual bool isBinaryPayload()
{ return true; }
};
class FormatFactory : public plugin::Plugin {
public:
using plugin::Plugin::Plugin;
virtual Format * make() = 0;
static
Format * make(json_t *json);
static
Format * make(const std::string &format);
};
template <typename T, const char *name, const char *desc, int flags = 0>
class FormatPlugin : public FormatFactory {
public:
using FormatFactory::FormatFactory;
virtual Format * make()
{
return new T(flags);
}
/// Get plugin name
virtual std::string
getName() const
{ return name; }
/// Get plugin description
virtual std::string
getDescription() const
{ return desc; }
};
} /* namespace node */
} /* namespace villas */

View file

@ -1,104 +0,0 @@
/** Read / write sample data in different formats.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <cstdio>
/* Forward declarations */
struct sample;
struct io;
struct format_type {
int (*init)(struct io *io);
int (*destroy)(struct io *io);
/** @{
* High-level interface
*/
/** Open an IO stream.
*
* @see fopen()
*/
int (*open)(struct io *io, const char *uri);
/** Close an IO stream.
*
* @see fclose()
*/
int (*close)(struct io *io);
/** Check if end-of-file was reached.
*
* @see feof()
*/
int (*eof)(struct io *io);
/** Rewind an IO stream.
*
* @see rewind()
*/
void (*rewind)(struct io *io);
/** Get a file descriptor which can be used with select / poll */
int (*fd)(struct io *io);
/** Flush buffered data to disk.
*
* @see fflush()
*/
int (*flush)(struct io *io);
int (*print)(struct io *io, struct sample *smps[], unsigned cnt);
int (*scan)( struct io *io, struct sample *smps[], unsigned cnt);
/** Print a header. */
void (*header)(struct io *io, const struct sample *smp);
/** Print a footer. */
void (*footer)(struct io *io);
/** @} */
/** @{
* Low-level interface
*/
/** @see format_type_sprint */
int (*sprint)(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);
/** @see format_type_sscan */
int (*sscan)(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt);
/** @} */
size_t size; /**< Number of bytes to allocate for io::_vd */
int flags; /**< A set of flags which is automatically used. */
char delimiter; /**< Newline delimiter. */
char separator; /**< Column separator (used by csv and villas.human formats only) */
};
struct format_type * format_type_lookup(const char *name);
const char * format_type_name(struct format_type *vt);

View file

@ -0,0 +1,78 @@
/** Comma-separated values.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <cstdlib>
#include <villas/formats/line.hpp>
/* Forward declarations. */
struct sample;
namespace villas {
namespace node {
class ColumnLineFormat : public LineFormat {
protected:
virtual size_t sprintLine(char *buf, size_t len, const struct sample *smp);
virtual size_t sscanLine(const char *buf, size_t len, struct sample *smp);
char separator; /**< Column separator */
public:
ColumnLineFormat(int fl, char delim, char sep) :
LineFormat(fl, delim),
separator(sep)
{ }
virtual void header(FILE *f, const struct vlist *sigs);
virtual void parse(json_t *json);
};
template <const char *name, const char *desc, int flags = 0, char delimiter = '\n', char separator = '\t'>
class ColumnLineFormatPlugin : public FormatFactory {
public:
using FormatFactory::FormatFactory;
virtual Format * make()
{
return new ColumnLineFormat(flags, delimiter, separator);
}
/// Get plugin name
virtual std::string
getName() const
{ return name; }
/// Get plugin description
virtual std::string
getDescription() const
{ return desc; }
};
} /* namespace node */
} /* namespace villas */

View file

@ -22,10 +22,23 @@
#pragma once
#include <jansson.h>
#include <villas/format.hpp>
/* Forward declarations */
struct sample;
struct io;
int iotagent_ul_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);
namespace villas {
namespace node {
class IotAgentUltraLightFormat : public Format {
protected:
int sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt);
int sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt);
public:
using Format::Format;
};
} /* namespace node */
} /* namespace villas */

View file

@ -1,35 +0,0 @@
/** JSON serializtion sample data.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <jansson.h>
/* Forward declarations */
struct sample;
int json_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);
int json_sscan(struct io *io, const char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);
int json_print(struct io *io, struct sample *smps[], unsigned cnt);
int json_scan(struct io *io, struct sample *smps[], unsigned cnt);

View file

@ -0,0 +1,66 @@
/** JSON serializtion sample data.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <jansson.h>
#include <villas/format.hpp>
/* Forward declarations */
struct sample;
namespace villas {
namespace node {
class JsonFormat : public Format {
protected:
static enum SignalType detect(const json_t *val);
json_t * packTimestamps(const struct sample *smp);
int unpackTimestamps(json_t *json_ts, struct sample *smp);
virtual int packSample(json_t **j, const struct sample *smp);
virtual int packSamples(json_t **j, const struct sample * const smps[], unsigned cnt);
virtual int unpackSample(json_t *json_smp, struct sample *smp);
virtual int unpackSamples(json_t *json_smps, struct sample * const smps[], unsigned cnt);
int dump_flags;
public:
JsonFormat(int fl) :
Format(fl),
dump_flags(0)
{ }
int sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt);
int sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt);
int print(FILE *f, const struct sample * const smps[], unsigned cnt);
int scan(FILE *f, struct sample * const smps[], unsigned cnt);
virtual void parse(json_t *json);
};
} /* namespace node */
} /* namespace villas */

View file

@ -22,14 +22,27 @@
#pragma once
#include <jansson.h>
#include <villas/signal_type.h>
#include <villas/formats/json.hpp>
/* Forward declarations */
struct sample;
struct io;
namespace villas {
namespace node {
int json_kafka_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);
int json_kafka_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt);
class JsonKafkaFormat : public JsonFormat {
int json_kafka_print(struct io *io, struct sample *smps[], unsigned cnt);
int json_kafka_scan(struct io *io, struct sample *smps[], unsigned cnt);
protected:
int packSample(json_t **j, const struct sample *smp);
int unpackSample(json_t *json_smp, struct sample *smp);
const char * villasToKafkaType(enum SignalType vt);
json_t *json_schema;
public:
JsonKafkaFormat(int fl);
virtual void parse(json_t *json);
};
} /* namespace node */
} /* namespace villas */

View file

@ -1,35 +0,0 @@
/** JSON serializtion for RESERVE project.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <jansson.h>
/* Forward declarations */
struct sample;
struct io;
int json_reserve_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);
int json_reserve_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt);
int json_reserve_print(struct io *io, struct sample *smps[], unsigned cnt);
int json_reserve_scan(struct io *io, struct sample *smps[], unsigned cnt);

View file

@ -1,6 +1,5 @@
/** The VILLASframework sample format
/** JSON serializtion for RESERVE project.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
@ -23,13 +22,20 @@
#pragma once
#include <cstdio>
#include <villas/formats/json.hpp>
/* Forward declarations */
struct io;
struct sample;
namespace villas {
namespace node {
void villas_human_header(struct io *io, const struct sample *smp);
class JsonReserveFormat : public JsonFormat {
int villas_human_print(struct io *io, struct sample *smps[], unsigned cnt);
int villas_human_scan(struct io *io, struct sample *smps[], unsigned cnt);
protected:
int packSample(json_t **j, const struct sample *smp);
int unpackSample(json_t *json_smp, struct sample *smp);
public:
using JsonFormat::JsonFormat;
};
} /* namespace node */
} /* namespace villas */

View file

@ -0,0 +1,95 @@
/** Line-based formats
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <villas/format.hpp>
namespace villas {
namespace node {
class LineFormat : public Format {
protected:
virtual size_t sprintLine(char *buf, size_t len, const struct sample *smp) = 0;
virtual size_t sscanLine(const char *buf, size_t len, struct sample *smp) = 0;
char delimiter; /**< Newline delimiter. */
char comment; /**< Prefix for comment lines. */
bool skip_first_line; /**< While reading, the first line is skipped (header) */
bool print_header; /**< Before any data, a header line is printed */
bool first_line_skipped;
bool header_printed;
public:
LineFormat(int fl, char delim = '\n', char com = '#') :
Format(fl),
delimiter(delim),
comment(com),
skip_first_line(false),
print_header(true),
first_line_skipped(false),
header_printed(false)
{ }
/** Print a header. */
virtual void header(FILE *f, const struct vlist *sigs)
{
header_printed = true;
}
virtual int sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt);
virtual int sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt);
virtual int scan(FILE *f, struct sample * const smps[], unsigned cnt);
virtual int print(FILE *f, const struct sample * const smps[], unsigned cnt);
virtual void parse(json_t *json);
};
template <typename T, const char *name, const char *desc, int flags = 0, char delimiter = '\n'>
class LineFormatPlugin : public FormatFactory {
public:
using FormatFactory::FormatFactory;
virtual Format * make()
{
return new T(flags, delimiter);
}
/// Get plugin name
virtual std::string
getName() const
{ return name; }
/// Get plugin description
virtual std::string
getDescription() const
{ return desc; }
};
} /* namespace node */
} /* namespace villas */

View file

@ -47,10 +47,10 @@ void msg_hdr_ntoh(struct msg *m);
* @retval 0 The message header is valid.
* @retval <0 The message header is invalid.
*/
int msg_verify(struct msg *m);
int msg_verify(const struct msg *m);
/** Copy fields from \p msg into \p smp. */
int msg_to_sample(struct msg *msg, struct sample *smp, struct vlist *signals);
int msg_to_sample(const struct msg *msg, struct sample *smp, const struct vlist *sigs);
/** Copy fields form \p smp into \p msg. */
int msg_from_sample(struct msg *msg, struct sample *smp, struct vlist *signals);
int msg_from_sample(struct msg *msg, const struct sample *smp, const struct vlist *sigs);

View file

@ -1,4 +1,4 @@
/** Message related functions
/** Protobuf IO format
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
@ -25,17 +25,28 @@
#include <cstdlib>
#include <villas/format.hpp>
/* Generated message descriptors by protoc */
#include <villas.pb-c.h>
/* Forward declarations. */
struct sample;
struct msg;
struct io;
enum villas_binary_flags {
VILLAS_BINARY_WEB = (1 << 16) /**< Use webmsg format (everying little endian) */
namespace villas {
namespace node {
class ProtobufFormat : public BinaryFormat {
protected:
enum SignalType detect(const Villas__Node__Value *val);
public:
using BinaryFormat::BinaryFormat;
int sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt);
int sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt);
};
/** Copy / read struct msg's from buffer \p buf to / fram samples \p smps. */
int villas_binary_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);
/** Read struct sample's from buffer \p buf into samples \p smps. */
int villas_binary_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt);
} /* namespace node */
} /* namespace villas */

View file

@ -23,8 +23,11 @@
#pragma once
#include <sstream>
#include <cstdlib>
#include <villas/format.hpp>
/* float128 is currently not yet supported as htole128() functions a missing */
#if 0 && defined(__GNUC__) && defined(__linux__)
#define HAS_128BIT
@ -33,23 +36,47 @@
/* Forward declarations */
struct sample;
enum raw_flags {
/** Treat the first three values as: sequenceno, seconds, nanoseconds */
RAW_FAKE_HEADER = (1 << 16),
RAW_BIG_ENDIAN = (1 << 17), /**< Encode data in big-endian byte order */
namespace villas {
namespace node {
RAW_BITS_8 = (3 << 24), /**< Pack each value as a byte. */
RAW_BITS_16 = (4 << 24), /**< Pack each value as a word. */
RAW_BITS_32 = (5 << 24), /**< Pack each value as a double word. */
RAW_BITS_64 = (6 << 24), /**< Pack each value as a quad word. */
#ifdef HAS_128BIT
RAW_128 = (7 << 24) /**< Pack each value as a double quad word. */
#endif
class RawFormat : public BinaryFormat {
public:
enum Endianess {
BIG,
LITTLE
};
protected:
enum Endianess endianess;
int bits;
bool fake;
public:
RawFormat(int fl, int b = 32, enum Endianess e = Endianess::LITTLE) :
BinaryFormat(fl),
endianess(e),
bits(b),
fake(false)
{
if (fake)
flags |= (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_TS_ORIGIN;
}
int sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt);
int sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt);
virtual void parse(json_t *json);
};
/** Copy / read struct msg's from buffer \p buf to / fram samples \p smps. */
int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);
class GtnetRawFormat : public RawFormat {
/** Read struct sample's from buffer \p buf into samples \p smps. */
int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt);
public:
GtnetRawFormat(int fl) :
RawFormat(fl, 32, Endianess::BIG)
{ }
};
} /* namespace node */
} /* namespace villas */

View file

@ -1,8 +1,8 @@
/** Comma-separated values.
/** The VILLASframework sample format
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC
* @copyright 2014-2021, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
@ -23,13 +23,21 @@
#pragma once
#include <cstdlib>
#include <cstdio>
/* Forward declarations. */
struct io;
struct sample;
#include <villas/format.hpp>
void csv_header(struct io *io, const struct sample *smp);
namespace villas {
namespace node {
int csv_sprint(struct io *io, char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt);
int csv_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt);
class ValueFormat : public Format {
public:
using Format::Format;
int sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt);
int sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt);
};
} /* namespace node */
} /* namespace villas */

View file

@ -0,0 +1,90 @@
/** Message related functions
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <cstdlib>
#include <villas/format.hpp>
/* Forward declarations. */
struct sample;
struct msg;
namespace villas {
namespace node {
class VillasBinaryFormat : public BinaryFormat {
public:
bool web;
VillasBinaryFormat(int fl, bool w) :
BinaryFormat(fl),
web(w)
{ }
int sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt);
int sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt);
};
template<bool web = false>
class VillasBinaryFormatPlugin : public FormatFactory {
public:
using FormatFactory::FormatFactory;
virtual Format * make()
{
return new VillasBinaryFormat((int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA, web);
}
/// Get plugin name
virtual std::string
getName() const
{
std::stringstream ss;
ss << "villas." << (web ? "web" : "binary");
return ss.str();
}
/// Get plugin description
virtual std::string
getDescription() const
{
std::stringstream ss;
ss << "VILLAS binary network format";
if (web)
ss << " for WebSockets";
return ss.str();
}
};
} /* namespace node */
} /* namespace villas */

View file

@ -1,4 +1,4 @@
/** Protobuf IO format
/** The VILLASframework sample format
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
@ -23,14 +23,24 @@
#pragma once
#include <cstdlib>
#include <cstdio>
/* Forward declarations */
struct sample;
#include <villas/formats/line.hpp>
/** Copy / read struct msg's from buffer \p buf to / fram samples \p smps. */
int protobuf_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);
namespace villas {
namespace node {
/** Read struct sample's from buffer \p buf into samples \p smps. */
int protobuf_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt);
class VILLASHumanFormat : public LineFormat {
protected:
size_t sprintLine(char *buf, size_t len, const struct sample *smp);
size_t sscanLine(const char *buf, size_t len, struct sample *smp);
public:
using LineFormat::LineFormat;
void header(FILE *f, const struct vlist *sigs);
};
} /* namespace node */
} /* namespace villas */

View file

@ -120,7 +120,7 @@ public:
}
/** Called whenever a sample is processed. */
virtual Reason process(sample *smp)
virtual Reason process(struct sample *smp)
{
return Reason::OK;
};
@ -135,7 +135,7 @@ public:
return flags;
}
virtual struct vlist *getSignals()
virtual struct vlist * getSignals()
{
return &signals;
}
@ -179,7 +179,7 @@ class HookFactory : public plugin::Plugin {
public:
using plugin::Plugin::Plugin;
virtual Hook *make(struct vpath *p, struct vnode *n) = 0;
virtual Hook * make(struct vpath *p, struct vnode *n) = 0;
virtual int getFlags() const = 0;
virtual int getPriority() const = 0;
@ -191,7 +191,7 @@ class HookPlugin : public HookFactory {
public:
using HookFactory::HookFactory;
virtual Hook *make(struct vpath *p, struct vnode *n)
virtual Hook * make(struct vpath *p, struct vnode *n)
{
return new T(p, n, getFlags(), getPriority());
}

View file

@ -65,7 +65,7 @@ int hook_list_prepare_signals(struct vlist *hs, struct vlist *signals);
int hook_list_add(struct vlist *hs, int mask, struct vpath *p, struct vnode *n);
int hook_list_process(struct vlist *hs, struct sample *smps[], unsigned cnt);
int hook_list_process(struct vlist *hs, struct sample * smps[], unsigned cnt);
void hook_list_periodic(struct vlist *hs);

View file

@ -1,141 +0,0 @@
/** Read / write sample data in different formats.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <villas/common.hpp>
#include <villas/node.h>
#include <villas/signal.h>
/* Forward declarations */
struct sample;
struct format_type;
enum class IOFlags {
/* Bits 0-7 are reserved for for flags defined by enum sample_flags */
FLUSH = (1 << 8), /**< Flush the output stream after each chunk of samples. */
NONBLOCK = (1 << 9), /**< Dont block io_read() while waiting for new samples. */
NEWLINES = (1 << 10), /**< The samples of this format are newline delimited. */
DESTROY_SIGNALS = (1 << 11), /**< Signal descriptors are managed by this IO instance. Destroy them in io_destoy() */
HAS_BINARY_PAYLOAD = (1 << 12) /**< This IO instance en/decodes binary payloads. */
};
enum class IOMode {
STDIO,
CUSTOM
};
struct io {
enum State state;
int flags;
char delimiter; /**< Newline delimiter. */
char separator; /**< Column separator (used by csv and villas.human formats only) */
struct io_direction {
/** A format type can use this file handle or overwrite the
* format::{open,close,eof,rewind} functions and the private
* data in io::_vd.
*/
FILE *stream;
char *buffer;
size_t buflen;
} in, out;
struct vlist *signals; /**< Signal meta data for parsed samples by io_scan() */
bool header_printed;
enum IOMode mode;
void *_vd;
const struct format_type *_vt;
};
int io_init(struct io *io, const struct format_type *fmt, struct vlist *signals, int flags) __attribute__ ((warn_unused_result));
int io_init2(struct io *io, const struct format_type *fmt, const char *dt, int flags) __attribute__ ((warn_unused_result));
int io_destroy(struct io *io) __attribute__ ((warn_unused_result));
int io_open(struct io *io, const char *uri);
int io_close(struct io *io);
void io_header(struct io *io, const struct sample *smp);
void io_footer(struct io *io);
int io_print(struct io *io, struct sample *smps[], unsigned cnt);
int io_scan(struct io *io, struct sample *smps[], unsigned cnt);
int io_eof(struct io *io);
void io_rewind(struct io *io);
int io_flush(struct io *io);
int io_fd(struct io *io);
const struct format_type * io_type(struct io *io);
int io_stream_open(struct io *io, const char *uri);
int io_stream_close(struct io *io);
int io_stream_eof(struct io *io);
void io_stream_rewind(struct io *io);
int io_stream_fd(struct io *io);
int io_stream_flush(struct io *io);
FILE * io_stream_input(struct io *io);
FILE * io_stream_output(struct io *io);
/** Parse samples from the buffer \p buf with a length of \p len bytes.
*
* @param buf[in] The buffer of data which should be parsed / de-serialized.
* @param len[in] The length of the buffer \p buf.
* @param rbytes[out] The number of bytes which have been read from \p buf.
* @param smps[out] The array of pointers to samples.
* @param cnt[in] The number of pointers in the array \p smps.
*
* @retval >=0 The number of samples which have been parsed from \p buf and written into \p smps.
* @retval <0 Something went wrong.
*/
int io_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt);
/** Print \p cnt samples from \p smps into buffer \p buf of length \p len.
*
* @param buf[out] The buffer which should be filled with serialized data.
* @param len[in] The length of the buffer \p buf.
* @param rbytes[out] The number of bytes which have been written to \p buf. Ignored if nullptr.
* @param smps[in] The array of pointers to samples.
* @param cnt[in] The number of pointers in the array \p smps.
*
* @retval >=0 The number of samples from \p smps which have been written into \p buf.
* @retval <0 Something went wrong.
*/
int io_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt);

View file

@ -73,7 +73,7 @@ struct mapping_entry {
* A value of 0 indicates that all remaining values starting from the offset of a sample should be mapped.
*/
int length;
unsigned offset; /**< Offset of this mapping entry within sample::data */
unsigned offset; /**< Offset of this mapping entry within sample::data */
union {
struct {

View file

@ -75,11 +75,6 @@ struct vnode {
uint64_t sequence; /**< This is a counter of received samples, in case the node-type does not generate sequence numbers itself. */
/** The path which uses this node as a destination.
* Usually every node should be used only by a single path as destination.
* Otherwise samples from different paths would be interleaved.
*/
struct vpath *output_path;
std::shared_ptr<villas::Stats> stats; /**< Statistic counters. This is a pointer to the statistic hooks private data. */
struct vnode_direction in, out;
@ -202,9 +197,9 @@ struct vlist * node_input_signals(struct vnode *n);
*/
int node_reverse(struct vnode *n);
int node_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int node_read(struct vnode *n, struct sample * smps[], unsigned cnt);
int node_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int node_write(struct vnode *n, struct sample * smps[], unsigned cnt);
int node_poll_fds(struct vnode *n, int fds[]);

View file

@ -35,6 +35,7 @@
/* Forward declarations */
struct vnode;
struct vpath;
enum class NodeDir {
IN, /**< VILLASnode is receiving/reading */
@ -45,6 +46,13 @@ struct vnode_direction {
enum State state;
enum NodeDir direction;
/** The path which uses this node as a source/destination.
*
* Usually every node should be used only by a single path as destination.
* Otherwise samples from different paths would be interleaved.
*/
struct vpath *path;
int enabled;
int builtin; /**< This node should use built-in hooks by default. */
unsigned vectorize; /**< Number of messages to send / recv at once (scatter / gather) */

View file

@ -197,7 +197,7 @@ struct vnode_type {
* @param release The number of samples that should be released after read is called.
* @return The number of messages actually received.
*/
int (*read)(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int (*read)(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** Send multiple messages in a single datagram / packet.
*
@ -214,7 +214,7 @@ struct vnode_type {
* @param release The number of samples that should be released after write is called
* @return The number of messages actually sent.
*/
int (*write)(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int (*write)(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** Reverse source and destination of a node.
*

View file

@ -33,10 +33,7 @@
#include <villas/node.h>
#include <villas/list.h>
#include <villas/io.h>
/* Forward declarations */
struct format_type;
#include <villas/format.hpp>
struct amqp_ssl_info {
int verify_peer;
@ -59,8 +56,7 @@ struct amqp {
amqp_connection_state_t producer;
amqp_connection_state_t consumer;
struct format_type *format;
struct io io;
villas::node::Format *formatter;
};
/** @see node_type::print */
@ -76,9 +72,9 @@ int amqp_start(struct vnode *n);
int amqp_stop(struct vnode *n);
/** @see node_type::read */
int amqp_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int amqp_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int amqp_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int amqp_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -82,10 +82,10 @@ int can_start(struct vnode *n);
int can_stop(struct vnode *n);
/** @see node_type::write */
int can_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int can_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::read */
int can_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int can_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::poll_fds */
int can_poll_fds(struct vnode *n, int fds[]);

View file

@ -93,9 +93,9 @@ int comedi_start(struct vnode *n);
int comedi_stop(struct vnode *n);
/** @see node_type::read */
int comedi_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int comedi_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int comedi_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int comedi_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -38,7 +38,7 @@
#include <villas/task.hpp>
#include <villas/queue_signalled.h>
#include <villas/common.hpp>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/config.h>
/* Include hard-coded Ethercat Bus configuration */
@ -109,9 +109,9 @@ int ethercat_start(struct vnode *n);
int ethercat_stop(struct vnode *n);
/** @see node_type::read */
int ethercat_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int ethercat_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int ethercat_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int ethercat_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -31,7 +31,7 @@
#include <villas/node/config.h>
#include <villas/node.h>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/timing.h>
struct example {
@ -82,10 +82,10 @@ int example_pause(struct vnode *n);
int example_resume(struct vnode *n);
/** @see node_type::write */
int example_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int example_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::read */
int example_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int example_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::reverse */
int example_reverse(struct vnode *n);

View file

@ -30,12 +30,11 @@
#pragma once
#include <villas/popen.hpp>
#include <villas/io.h>
#include <villas/format.hpp>
/* Forward declarations */
struct vnode;
struct sample;
struct format_type;
/** Node-type for signal generation.
* @see node_type
@ -49,8 +48,8 @@ struct exec {
std::string command;
villas::utils::Popen::arg_list arguments;
villas::utils::Popen::env_map environment;
struct format_type *format;
struct io io;
villas::node::Format *formatter;
};
/** @see node_type::print */
@ -66,9 +65,9 @@ int exec_open(struct vnode *n);
int exec_close(struct vnode *n);
/** @see node_type::read */
int exec_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int exec_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int exec_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int exec_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -29,15 +29,18 @@
#pragma once
#include <villas/io.h>
#include <cstdio>
#include <villas/format.hpp>
#include <villas/node.h>
#include <villas/task.hpp>
#define FILE_MAX_PATHLEN 512
struct file {
struct io io; /**< Format and file IO */
struct format_type *format;
villas::node::Format *formatter;
FILE *stream_in;
FILE *stream_out;
char *uri_tmpl; /**< Format string for file name. */
char *uri; /**< Real file name. */
@ -82,9 +85,9 @@ int file_start(struct vnode *n);
int file_stop(struct vnode *n);
/** @see node_type::read */
int file_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int file_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int file_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int file_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -31,7 +31,7 @@
#include <villas/node/config.h>
#include <villas/node.h>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/timing.h>
#include <villas/fpga/card.hpp>
@ -95,10 +95,10 @@ int fpga_start(struct vnode *n);
int fpga_stop(struct vnode *n);
/** @see node_type::write */
int fpga_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int fpga_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::read */
int fpga_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int fpga_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::poll_fds */
int fpga_poll_fds(struct vnode *n, int fds[]);

View file

@ -96,10 +96,10 @@ int iec61850_sv_stop(struct vnode *n);
int iec61850_sv_destroy(struct vnode *n);
/** @see node_type::read */
int iec61850_sv_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int iec61850_sv_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int iec61850_sv_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int iec61850_sv_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::fd */
int iec61850_sv_fd(struct vnode *n);

View file

@ -31,7 +31,7 @@
#include <villas/node.h>
#include <villas/pool.h>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/queue_signalled.h>
#include <rdma/rdma_cma.h>
@ -128,9 +128,9 @@ int ib_destroy(struct vnode *n);
int ib_stop(struct vnode *n);
/** @see node_type::read */
int ib_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int ib_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int ib_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int ib_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -61,6 +61,6 @@ int influxdb_open(struct vnode *n);
int influxdb_close(struct vnode *n);
/** @see node_type::write */
int influxdb_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int influxdb_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -33,13 +33,10 @@
#include <villas/node.h>
#include <villas/pool.h>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/queue_signalled.h>
/* Forward declarations */
struct format_type;
struct kafka {
struct queue_signalled queue;
struct pool pool;
@ -71,8 +68,7 @@ struct kafka {
char *password; /**< SSL certificate. */
} sasl;
struct format_type *format;
struct io io;
villas::node::Format *formatter;
};
/** @see node_type::reverse */
@ -103,9 +99,9 @@ int kafka_type_start(villas::node::SuperNode *sn);
int kafka_type_stop();
/** @see node_type::read */
int kafka_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int kafka_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int kafka_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int kafka_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -58,9 +58,9 @@ int loopback_open(struct vnode *n);
int loopback_close(struct vnode *n);
/** @see node_type::read */
int loopback_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int loopback_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int loopback_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int loopback_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -56,10 +56,10 @@ int loopback_internal_start(struct vnode *n);
int loopback_internal_stop(struct vnode *n);
/** @see node_type::read */
int loopback_internal_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int loopback_internal_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int loopback_internal_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int loopback_internal_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
struct vnode * loopback_internal_create(struct vnode *orig);

View file

@ -31,11 +31,10 @@
#include <villas/node.h>
#include <villas/pool.h>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/queue_signalled.h>
/* Forward declarations */
struct format_type;
struct mosquitto;
struct mqtt {
@ -62,8 +61,7 @@ struct mqtt {
char *keyfile; /**< SSL private key. */
} ssl;
struct format_type *format;
struct io io;
villas::node::Format *formatter;
};
/** @see node_type::reverse */
@ -94,9 +92,9 @@ int mqtt_type_start(villas::node::SuperNode *sn);
int mqtt_type_stop();
/** @see node_type::read */
int mqtt_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int mqtt_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int mqtt_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int mqtt_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -31,22 +31,18 @@
#include <villas/node.h>
#include <villas/list.h>
#include <villas/io.h>
#include <villas/format.hpp>
/** The maximum length of a packet which contains stuct msg. */
#define NANOMSG_MAX_PACKET_LEN 1500
/* Forward declarations */
struct format_type;
struct nanomsg {
struct {
int socket;
struct vlist endpoints;
} in, out;
struct format_type *format;
struct io io;
villas::node::Format *formatter;
};
/** @see node_type::print */
@ -62,9 +58,9 @@ int nanomsg_start(struct vnode *n);
int nanomsg_stop(struct vnode *n);
/** @see node_type::read */
int nanomsg_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int nanomsg_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int nanomsg_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int nanomsg_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -96,9 +96,9 @@ int ngsi_stop(struct vnode *n);
int ngsi_reverse(struct vnode *n);
/** @see node_type::read */
int ngsi_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int ngsi_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int ngsi_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int ngsi_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -80,9 +80,9 @@ int opal_start(struct vnode *n);
int opal_stop(struct vnode *n);
/** @see node_type::read */
int opal_read(struct vnode *n, struct sample *smps[], unsigned cnt);
int opal_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int opal_write(struct vnode *n, struct sample *smps[], unsigned cnt);
int opal_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -37,7 +37,7 @@
#include <villas/node.h>
#include <villas/list.h>
#include <villas/log.hpp>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/queue_signalled.h>
#include <villas/hooks/limit_rate.hpp>
#include <villas/hooks/decimate.hpp>
@ -48,9 +48,6 @@ extern "C" {
#include <re/re_rtp.h>
}
/* Forward declarations */
struct format_type;
/** The maximum length of a packet which contains rtp data. */
#define RTP_INITIAL_BUFFER_LEN 1500
#define RTP_PACKET_TYPE 21
@ -69,8 +66,7 @@ struct rtp {
struct sa saddr_rtcp; /**< Local/Remote address of the RTCP socket */
} in, out;
struct format_type *format;
struct io io;
villas::node::Format *formatter;
struct {
int enabled;
@ -116,9 +112,9 @@ int rtp_start(struct vnode *n);
int rtp_stop(struct vnode *n);
/** @see node_type::read */
int rtp_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int rtp_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int rtp_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int rtp_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -60,9 +60,9 @@ int shmem_start(struct vnode *n);
int shmem_stop(struct vnode *n);
/** @see node_type::read */
int shmem_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int shmem_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int shmem_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int shmem_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -89,6 +89,6 @@ int signal_generator_start(struct vnode *n);
int signal_generator_stop(struct vnode *n);
/** @see node_type::read */
int signal_generator_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int signal_generator_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -32,10 +32,7 @@
#include <villas/node/config.h>
#include <villas/node.h>
#include <villas/socket_addr.h>
#include <villas/io.h>
/* Forward declarations */
struct format_type;
#include <villas/format.hpp>
/** The maximum length of a packet which contains stuct msg. */
#define SOCKET_INITIAL_BUFFER_LEN (64*1024)
@ -46,8 +43,7 @@ struct socket {
enum SocketLayer layer; /**< The OSI / IP layer which should be used for this socket */
struct format_type *format;
struct io io;
villas::node::Format *formatter;
/* Multicast options */
struct multicast {
@ -78,10 +74,10 @@ int socket_start(struct vnode *n);
int socket_stop(struct vnode *n);
/** @see node_type::write */
int socket_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int socket_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::read */
int socket_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int socket_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::parse */
int socket_parse(struct vnode *n, json_t *json);

View file

@ -70,6 +70,6 @@ int stats_node_start(struct vnode *n);
int stats_node_stop(struct vnode *n);
/** @see node_type::read */
int stats_node_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int stats_node_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -30,7 +30,7 @@
#pragma once
#include <villas/list.h>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/task.hpp>
/* Forward declarations */
@ -41,7 +41,7 @@ struct sample;
struct test_rtt_case {
double rate;
unsigned values;
unsigned limit; /**< The number of samples we take per test. */
unsigned limit; /**< The number of samples we take per test. */
char *filename;
char *filename_formatted;
@ -50,19 +50,19 @@ struct test_rtt_case {
};
struct test_rtt {
struct Task task; /**< The periodic task for test_rtt_read() */
struct io io; /**< The format of the output file */
struct format_type *format;
struct Task task; /**< The periodic task for test_rtt_read() */
villas::node::Format *formatter;/**< The format of the output file */
FILE *stream;
double cooldown; /**< Number of seconds to wait beween tests. */
double cooldown; /**< Number of seconds to wait beween tests. */
int current; /**< Index of current test in test_rtt::cases */
int current; /**< Index of current test in test_rtt::cases */
int counter;
struct vlist cases; /**< List of test cases */
struct vlist cases; /**< List of test cases */
char *output; /**< The directory where we place the results. */
char *prefix; /**< An optional prefix in the filename. */
char *output; /**< The directory where we place the results. */
char *prefix; /**< An optional prefix in the filename. */
};
/** @see node_type::print */
@ -78,9 +78,9 @@ int test_rtt_start(struct vnode *n);
int test_rtt_stop(struct vnode *n);
/** @see node_type::read */
int test_rtt_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int test_rtt_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int test_rtt_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int test_rtt_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -34,7 +34,7 @@
#include <villas/queue_signalled.h>
#include <villas/common.hpp>
#include <villas/buffer.hpp>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/node/config.h>
#define DEFAULT_WEBSOCKET_QUEUE_LENGTH (DEFAULT_QUEUE_LENGTH * 64)
@ -70,10 +70,9 @@ struct websocket_connection {
struct lws *wsi;
struct vnode *node;
struct io io;
villas::node::Format *formatter;
struct queue queue; /**< For samples which are sent to the Websocket */
struct format_type *format;
struct websocket_destination *destination;
struct {
@ -107,9 +106,9 @@ int websocket_stop(struct vnode *n);
int websocket_destroy(struct vnode *n);
/** @see node_type::read */
int websocket_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int websocket_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int websocket_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int websocket_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -32,23 +32,22 @@
#include <cstdint>
#include <jansson.h>
#include <villas/super_node.hpp>
#include <villas/list.h>
#include <villas/io.h>
#include <villas/format.hpp>
#if ZMQ_BUILD_DRAFT_API && (ZMQ_VERSION_MAJOR > 4 || (ZMQ_VERSION_MAJOR == 4 && ZMQ_VERSION_MINOR >= 2))
#define ZMQ_BUILD_DISH 1
#endif
/* Forward declarations */
struct format_type;
struct vnode;
struct sample;
struct zeromq {
int ipv6;
struct format_type *format;
struct io io;
villas::node::Format *formatter;
struct Curve {
int enabled;
@ -93,9 +92,9 @@ int zeromq_start(struct vnode *n);
int zeromq_stop(struct vnode *n);
/** @see node_type::read */
int zeromq_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int zeromq_read(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @see node_type::write */
int zeromq_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release);
int zeromq_write(struct vnode *n, struct sample * const smps[], unsigned cnt);
/** @} */

View file

@ -79,7 +79,8 @@ struct vpath {
struct Task timeout;
double rate; /**< A timeout for */
int enabled; /**< Is this path enabled. */
int enabled; /**< Is this path enabled? */
int muxed; /**< Is this path muxed? */
int affinity; /**< Thread affinity. */
int poll; /**< Weather or not to use poll(2). */
int reverse; /**< This path has a matching reverse path. */
@ -163,6 +164,8 @@ void path_parse_mask(struct vpath *p, json_t *json_mask, struct vlist *nodes);
bool path_is_simple(const struct vpath *p);
bool path_is_muxed(const struct vpath *p);
bool path_is_enabled(const struct vpath *p);
bool path_is_reversed(const struct vpath *p);

View file

@ -49,7 +49,7 @@ int path_destination_prepare(struct vpath_destination *pd, int queuelen);
void path_destination_check(struct vpath_destination *pd);
void path_destination_enqueue(struct vpath *p, struct sample *smps[], unsigned cnt);
void path_destination_enqueue(struct vpath *p, const struct sample * const smps[], unsigned cnt);
void path_destination_write(struct vpath_destination *pd, struct vpath *p);

View file

@ -45,12 +45,12 @@ struct vpath_source {
struct vnode *node;
bool masked;
enum PathSourceType type;
struct pool pool;
struct vlist mappings; /**< List of mappings (struct mapping_entry). */
struct vlist secondaries;
struct vlist secondaries; /**< List of secondary path sources (struct path_sourced). */
};
int path_source_init_master(struct vpath_source *ps, struct vnode *n) __attribute__ ((warn_unused_result));

View file

@ -26,13 +26,11 @@
#include <villas/common.hpp>
#include <villas/utils.hpp>
#include <villas/node_type.h>
#include <villas/format_type.h>
extern struct vlist plugins;
enum PluginType {
NODE,
FORMAT,
NODE
};
struct plugin {
@ -42,13 +40,12 @@ struct plugin {
enum PluginType type;
union {
struct format_type format;
struct vnode_type node;
};
};
/** Return a pointer to the plugin structure */
#define plugin(vt) ((struct plugin *) ((char *) (vt) - offsetof(struct plugin, format)))
#define plugin(vt) ((struct plugin *) ((char *) (vt) - offsetof(struct plugin, node)))
#define plugin_name(vt) plugin(vt)->name
#define plugin_description(vt) plugin(vt)->description

View file

@ -120,7 +120,7 @@ int sample_incref(struct sample *s);
/** Decrease reference count and release memory if last reference was held. */
int sample_decref(struct sample *s);
int sample_copy(struct sample *dst, struct sample *src);
int sample_copy(struct sample *dst, const struct sample *src);
/** Dump all details about a sample to debug log */
void sample_dump(villas::Logger logger, struct sample *s);
@ -128,13 +128,12 @@ void sample_dump(villas::Logger logger, struct sample *s);
/** Compare two samples */
int sample_cmp(struct sample *a, struct sample *b, double epsilon, int flags);
int sample_clone_many(struct sample *clones[], struct sample *origs[], int cnt);
int sample_copy_many(struct sample *dsts[], struct sample *srcs[], int cnt);
int sample_incref_many(struct sample *smps[], int cnt);
int sample_decref_many(struct sample *smps[], int cnt);
int sample_clone_many(struct sample *dsts[], const struct sample * const srcs[], int cnt);
int sample_copy_many(struct sample * const dsts[], const struct sample * const srcs[], int cnt);
int sample_incref_many(struct sample * const smps[], int cnt);
int sample_decref_many(struct sample * const smps[], int cnt);
enum SignalType sample_format(const struct sample *s, unsigned idx);
void sample_data_insert(struct sample *smp, const union signal_data *src, size_t offset, size_t len);
void sample_data_remove(struct sample *smp, size_t offset, size_t len);

View file

@ -96,7 +96,7 @@ int shmem_int_close(struct shmem_int *shm);
* @retval >=0 Number of samples that were read. Can be less than cnt (including 0) in case not enough samples were available.
* @retval -1 The other process closed the interface; no samples can be read anymore.
*/
int shmem_int_read(struct shmem_int *shm, struct sample *smps[], unsigned cnt);
int shmem_int_read(struct shmem_int *shm, struct sample * const smps[], unsigned cnt);
/** Write samples to the interface.
*
@ -106,7 +106,7 @@ int shmem_int_read(struct shmem_int *shm, struct sample *smps[], unsigned cnt);
* @retval >=0 Number of samples that were successfully written. Can be less than cnt (including 0) in case of a full queue.
* @retval -1 The write failed for some reason; no more samples can be written.
*/
int shmem_int_write(struct shmem_int *shm, struct sample *smps[], unsigned cnt);
int shmem_int_write(struct shmem_int *shm, const struct sample * const smps[], unsigned cnt);
/** Allocate samples to be written to the interface.
*

View file

@ -63,12 +63,12 @@ union signal_data {
void signal_data_cast(union signal_data *data, enum SignalType from, enum SignalType to);
/** Print value of a signal to a character buffer. */
int signal_data_print_str(const union signal_data *data, enum SignalType type, char *buf, size_t len);
int signal_data_print_str(const union signal_data *data, enum SignalType type, char *buf, size_t len, int precision = 5);
int signal_data_parse_str(union signal_data *data, enum SignalType type, const char *ptr, char **end);
int signal_data_parse_json(union signal_data *data, enum SignalType type, json_t *json);
json_t * signal_data_to_json(union signal_data *data, enum SignalType type);
json_t * signal_data_to_json(const union signal_data *data, enum SignalType type);
void signal_data_set(union signal_data *data, enum SignalType type, double val);

View file

@ -48,6 +48,7 @@ set(LIB_SRC
config_helper.cpp
config.cpp
dumper.cpp
format.cpp
mapping.cpp
memory.cpp
memory/heap.cpp
@ -65,15 +66,13 @@ set(LIB_SRC
queue.cpp
sample.cpp
shmem.cpp
signal.cpp
signal_data.cpp
signal_list.cpp
signal_type.cpp
signal.cpp
socket_addr.cpp
stats.cpp
super_node.cpp
socket_addr.cpp
io.cpp
format_type.cpp
)
if(WITH_WEB)

View file

@ -23,6 +23,7 @@
#include <villas/config.h>
#include <villas/plugin.h>
#include <villas/hook.hpp>
#include <villas/format.hpp>
#include <villas/api/request.hpp>
#include <villas/api/response.hpp>
@ -49,18 +50,31 @@ public:
if (body != nullptr)
throw BadRequest("Capabilities endpoint does not accept any body data");
for (auto f : plugin::Registry::lookup<RequestFactory>()) {
json_name = json_string(f->getName().c_str());
for (auto p : plugin::Registry::lookup<RequestFactory>()) {
json_name = json_string(p->getName().c_str());
json_array_append_new(json_apis, json_name);
}
for (auto f : plugin::Registry::lookup<HookFactory>()) {
json_name = json_string(f->getName().c_str());
for (auto p : plugin::Registry::lookup<HookFactory>()) {
json_name = json_string(p->getName().c_str());
json_array_append_new(json_hooks, json_name);
}
for (auto p : plugin::Registry::lookup<FormatFactory>()) {
json_name = json_string(p->getName().c_str());
json_array_append_new(json_formats, json_name);
}
#if 0 /* @todo Port to C++ */
for (auto f : NodeFactory::lookup()) {
json_name = json_string(f->getName().c_str());
json_array_append_new(json_nodes, json_name);
}
#else
for (size_t i = 0; i < vlist_length(&plugins); i++) {
struct plugin *p = (struct plugin *) vlist_at(&plugins, i);
@ -70,26 +84,8 @@ public:
json_name = json_string(p->name);
json_array_append_new(json_nodes, json_name);
break;
case PluginType::FORMAT:
json_name = json_string(p->name);
json_array_append_new(json_formats, json_name);
break;
}
}
#if 0 /* @todo Port to C++ */
for (auto f : NodeFactory::lookup()) {
json_name = json_string(f->getName().c_str());
json_array_append_new(json_nodes, json_name);
}
for (auto f : FormatFactory::lookup()) {
json_name = json_string(f->getName().c_str());
json_array_append_new(json_formats, json_name);
}
#endif
auto *json_capabilities = json_pack("{ s: o, s: o, s: o, s: o }",

View file

@ -26,7 +26,7 @@
#include <villas/api/response.hpp>
#include <villas/nodes/file.hpp>
#include <villas/io.h>
#include <villas/format.hpp>
namespace villas {
namespace node {
@ -55,7 +55,7 @@ public:
struct file *f = (struct file *) node->_vd;
if (matches[2] == "rewind")
io_rewind(&f->io);
rewind(f->stream_in);
return new Response(session, HTTP_STATUS_OK);
}

196
lib/format.cpp Normal file
View file

@ -0,0 +1,196 @@
/** Reading and writing simulation samples in various formats.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <cstdlib>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <cctype>
#include <villas/format.hpp>
#include <villas/utils.hpp>
#include <villas/sample.h>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
Format * FormatFactory::make(json_t *json)
{
std::string type;
FormatFactory *ff;
Format *f;
if (json_is_string(json)) {
type = json_string_value(json);
return FormatFactory::make(type);
}
else if (json_is_object(json)) {
json_t *json_type = json_object_get(json, "type");
type = json_string_value(json_type);
ff = plugin::Registry::lookup<FormatFactory>(type);
if (!ff)
throw ConfigError(json, "Unknown format: {}", type);
f = ff->make();
f->parse(json);
return f;
}
else
throw ConfigError(json, "Invalid format config");
}
Format * FormatFactory::make(const std::string &format)
{
FormatFactory *ff = plugin::Registry::lookup<FormatFactory>(format);
if (!ff)
throw RuntimeError("Unknown format: {}", format);
return ff->make();
}
Format::Format(int fl) :
flags(fl),
real_precision(17),
destroy_signals(false),
signals(nullptr)
{
in.buflen =
out.buflen = 4096;
in.buffer = new char[in.buflen];
out.buffer = new char[out.buflen];
if (!in.buffer || !out.buffer)
throw MemoryAllocationError();
}
Format::~Format()
{
int ret __attribute__((unused));
delete[] in.buffer;
delete[] out.buffer;
if (signals && destroy_signals)
ret = vlist_destroy(signals, (dtor_cb_t) signal_decref, false);
}
void Format::start(struct vlist *sigs, int fl)
{
flags &= fl;
signals = sigs;
start();
}
void Format::start(const std::string &dtypes, int fl)
{
int ret;
flags |= fl;
signals = new struct vlist;
if (!signals)
throw MemoryAllocationError();
ret = vlist_init(signals);
if (ret)
throw RuntimeError("Failed to initialize list");
ret = signal_list_generate2(signals, dtypes.c_str());
if (ret)
throw RuntimeError("Failed to generate signal list");
destroy_signals = true;
start();
}
int Format::print(FILE *f, const struct sample * const smps[], unsigned cnt)
{
int ret;
size_t wbytes;
ret = sprint(out.buffer, out.buflen, &wbytes, smps, cnt);
fwrite(out.buffer, wbytes, 1, f);
return ret;
}
int Format::scan(FILE *f, struct sample * const smps[], unsigned cnt)
{
size_t bytes, rbytes;
bytes = fread(in.buffer, 1, in.buflen, f);
return sscan(in.buffer, bytes, &rbytes, smps, cnt);
}
void Format::parse(json_t *json)
{
int ret;
json_error_t err;
int ts_origin = -1;
int ts_received = -1;
int sequence = -1;
int data = -1;
int offset = -1;
ret = json_unpack_ex(json, &err, 0, "{ s?: b, s?: b, s?: b, s?: b, s?: b, s?: i }",
"ts_origin", &ts_origin,
"ts_received", &ts_received,
"sequence", &sequence,
"data", &data,
"offset", &offset,
"real_precision", &real_precision
);
if (ret)
throw ConfigError(json, err, "node-config-format", "Failed to parse format configuration");
if (real_precision < 0 || real_precision > 31)
throw ConfigError(json, err, "node-config-format-precision", "The valid range for the real_precision setting is between 0 and 31 (inclusive)");
if (ts_origin == 0)
flags &= ~ (int) SampleFlags::HAS_TS_ORIGIN;
if (ts_received == 0)
flags &= ~ (int) SampleFlags::HAS_TS_RECEIVED;
if (sequence == 0)
flags &= ~ (int) SampleFlags::HAS_SEQUENCE;
if (data == 0)
flags &= ~ (int) SampleFlags::HAS_DATA;
if (offset == 0)
flags &= ~ (int) SampleFlags::HAS_OFFSET;
}

View file

@ -1,43 +0,0 @@
/** Read / write sample data in different formats.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <cstdlib>
#include <cstdio>
#include <villas/plugin.h>
#include <villas/format_type.h>
struct format_type * format_type_lookup(const char *name)
{
struct plugin *p;
p = plugin_lookup(PluginType::FORMAT, name);
if (!p)
return nullptr;
return &p->format;
}
const char * format_type_name(struct format_type *vt)
{
return plugin_name(vt);
}

View file

@ -60,16 +60,17 @@ if(DEFINED PROTOBUFC_COMPILER AND PROTOBUFC_FOUND)
endif()
list(APPEND FORMAT_SRC
json.cpp
column.cpp
iotagent_ul.cpp
json_reserve.cpp
json_kafka.cpp
json_reserve.cpp
json.cpp
line.cpp
msg.cpp
raw.cpp
value.cpp
villas_binary.cpp
villas_human.cpp
csv.cpp
raw.cpp
msg.cpp
value.cpp
)
add_library(formats STATIC ${FORMAT_SRC})

207
lib/formats/column.cpp Normal file
View file

@ -0,0 +1,207 @@
/** Comma-separated values.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <cctype>
#include <cinttypes>
#include <cstring>
#include <villas/formats/column.hpp>
#include <villas/sample.h>
#include <villas/signal.h>
#include <villas/timing.h>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
size_t ColumnLineFormat::sprintLine(char *buf, size_t len, const struct sample *smp)
{
size_t off = 0;
struct signal *sig;
if (smp->flags & (int) SampleFlags::HAS_TS_ORIGIN)
off += snprintf(buf + off, len - off, "%lld%c%09lld", (long long) smp->ts.origin.tv_sec, separator,
(long long) smp->ts.origin.tv_nsec);
else
off += snprintf(buf + off, len - off, "nan%cnan", separator);
if (smp->flags & (int) SampleFlags::HAS_TS_RECEIVED)
off += snprintf(buf + off, len - off, "%c%.09f", separator, time_delta(&smp->ts.origin, &smp->ts.received));
else
off += snprintf(buf + off, len - off, "%cnan", separator);
if (smp->flags & (int) SampleFlags::HAS_SEQUENCE)
off += snprintf(buf + off, len - off, "%c%" PRIu64, separator, smp->sequence);
else
off += snprintf(buf + off, len - off, "%cnan", separator);
for (unsigned i = 0; i < smp->length; i++) {
sig = (struct signal *) vlist_at_safe(smp->signals, i);
if (!sig)
break;
off += snprintf(buf + off, len - off, "%c", separator);
off += signal_data_print_str(&smp->data[i], sig->type, buf + off, len - off, real_precision);
}
off += snprintf(buf + off, len - off, "%c", delimiter);
return off;
}
size_t ColumnLineFormat::sscanLine(const char *buf, size_t len, struct sample *smp)
{
int ret;
unsigned i = 0;
const char *ptr = buf;
char *end;
struct timespec offset;
smp->flags = 0;
smp->signals = signals;
smp->ts.origin.tv_sec = strtoul(ptr, &end, 10);
if (end == ptr || *end == delimiter)
goto out;
ptr = end + 1;
smp->ts.origin.tv_nsec = strtoul(ptr, &end, 10);
if (end == ptr || *end == delimiter)
goto out;
ptr = end + 1;
smp->flags |= (int) SampleFlags::HAS_TS_ORIGIN;
offset = time_from_double(strtof(ptr, &end));
if (end == ptr || *end == delimiter)
goto out;
smp->ts.received = time_add(&smp->ts.origin, &offset);
smp->flags |= (int) SampleFlags::HAS_TS_RECEIVED;
ptr = end + 1;
smp->sequence = strtoul(ptr, &end, 10);
if (end == ptr || *end == delimiter)
goto out;
smp->flags |= (int) SampleFlags::HAS_SEQUENCE;
for (ptr = end + 1, i = 0; i < smp->capacity; ptr = end + 1, i++) {
if (*end == delimiter)
goto out;
struct signal *sig = (struct signal *) vlist_at_safe(smp->signals, i);
if (!sig)
goto out;
ret = signal_data_parse_str(&smp->data[i], sig->type, ptr, &end);
if (ret || end == ptr) /* There are no valid values anymore. */
goto out;
}
out: if (*end == delimiter)
end++;
smp->length = i;
if (smp->length > 0)
smp->flags |= (int) SampleFlags::HAS_DATA;
return end - buf;
}
void ColumnLineFormat::header(FILE *f, const struct vlist *sigs)
{
/* Abort if we are not supposed to, or have already printed the header */
if (!print_header || header_printed)
return;
if (comment)
fprintf(f, "%c", comment);
if (flags & (int) SampleFlags::HAS_TS_ORIGIN)
fprintf(f, "secs%cnsecs%c", separator, separator);
if (flags & (int) SampleFlags::HAS_OFFSET)
fprintf(f, "offset%c", separator);
if (flags & (int) SampleFlags::HAS_SEQUENCE)
fprintf(f, "sequence%c", separator);
if (flags & (int) SampleFlags::HAS_DATA) {
for (unsigned i = 0; i < vlist_length(sigs); i++) {
struct signal *sig = (struct signal *) vlist_at_safe(sigs, i);
if (!sig)
break;
if (sig->name)
fprintf(f, "%s", sig->name);
else
fprintf(f, "signal%u", i);
if (sig->unit)
fprintf(f, "[%s]", sig->unit);
if (i + 1 < vlist_length(sigs))
fprintf(f, "%c", separator);
}
}
fprintf(f, "%c", delimiter);
LineFormat::header(f, sigs);
}
void ColumnLineFormat::parse(json_t *json)
{
int ret;
json_error_t err;
const char *sep = nullptr;
ret = json_unpack_ex(json, &err, 0, "{ s?: s }",
"separator", &sep
);
if (ret)
throw ConfigError(json, err, "node-config-format-column", "Failed to parse format configuration");
if (sep) {
if (strlen(sep) != 1)
throw ConfigError(json, "node-config-format-column-separator", "Column separator must be a single character!");
separator = sep[0];
}
LineFormat::parse(json);
}
static char n1[] = "csv";
static char d1[] = "Comma-separated values";
static ColumnLineFormatPlugin<n1, d1, (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA, '\n', ','> p1;
static char n2[] = "tsv";
static char d2[] = "Tabulator-separated values";
static ColumnLineFormatPlugin<n2, d2, (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA, '\n', '\t'> p2;

View file

@ -1,238 +0,0 @@
/** Comma-separated values.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <cctype>
#include <cinttypes>
#include <cstring>
#include <villas/io.h>
#include <villas/formats/csv.h>
#include <villas/plugin.h>
#include <villas/sample.h>
#include <villas/signal.h>
#include <villas/timing.h>
using namespace villas::utils;
static size_t csv_sprint_single(struct io *io, char *buf, size_t len, const struct sample *smp)
{
size_t off = 0;
struct signal *sig;
if (smp->flags & (int) SampleFlags::HAS_TS_ORIGIN)
off += snprintf(buf + off, len - off, "%lld%c%09lld", (long long) smp->ts.origin.tv_sec, io->separator,
(long long) smp->ts.origin.tv_nsec);
else
off += snprintf(buf + off, len - off, "nan%cnan", io->separator);
if (smp->flags & (int) SampleFlags::HAS_TS_RECEIVED)
off += snprintf(buf + off, len - off, "%c%.09f", io->separator, time_delta(&smp->ts.origin, &smp->ts.received));
else
off += snprintf(buf + off, len - off, "%cnan", io->separator);
if (smp->flags & (int) SampleFlags::HAS_SEQUENCE)
off += snprintf(buf + off, len - off, "%c%" PRIu64, io->separator, smp->sequence);
else
off += snprintf(buf + off, len - off, "%cnan", io->separator);
for (unsigned i = 0; i < smp->length; i++) {
sig = (struct signal *) vlist_at_safe(smp->signals, i);
if (!sig)
break;
off += snprintf(buf + off, len - off, "%c", io->separator);
off += signal_data_print_str(&smp->data[i], sig->type, buf + off, len - off);
}
off += snprintf(buf + off, len - off, "%c", io->delimiter);
return off;
}
static size_t csv_sscan_single(struct io *io, const char *buf, size_t len, struct sample *smp)
{
int ret;
unsigned i = 0;
const char *ptr = buf;
char *end;
struct timespec offset;
smp->flags = 0;
smp->signals = io->signals;
smp->ts.origin.tv_sec = strtoul(ptr, &end, 10);
if (end == ptr || *end == io->delimiter)
goto out;
ptr = end + 1;
smp->ts.origin.tv_nsec = strtoul(ptr, &end, 10);
if (end == ptr || *end == io->delimiter)
goto out;
ptr = end + 1;
smp->flags |= (int) SampleFlags::HAS_TS_ORIGIN;
offset = time_from_double(strtof(ptr, &end));
if (end == ptr || *end == io->delimiter)
goto out;
smp->ts.received = time_add(&smp->ts.origin, &offset);
smp->flags |= (int) SampleFlags::HAS_TS_RECEIVED;
ptr = end + 1;
smp->sequence = strtoul(ptr, &end, 10);
if (end == ptr || *end == io->delimiter)
goto out;
smp->flags |= (int) SampleFlags::HAS_SEQUENCE;
for (ptr = end + 1, i = 0; i < smp->capacity; ptr = end + 1, i++) {
if (*end == io->delimiter)
goto out;
struct signal *sig = (struct signal *) vlist_at_safe(smp->signals, i);
if (!sig)
goto out;
ret = signal_data_parse_str(&smp->data[i], sig->type, ptr, &end);
if (ret || end == ptr) /* There are no valid values anymore. */
goto out;
}
out: if (*end == io->delimiter)
end++;
smp->length = i;
if (smp->length > 0)
smp->flags |= (int) SampleFlags::HAS_DATA;
return end - buf;
}
int csv_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
{
unsigned i;
size_t off = 0;
for (i = 0; i < cnt && off < len; i++)
off += csv_sprint_single(io, buf + off, len - off, smps[i]);
if (wbytes)
*wbytes = off;
return i;
}
int csv_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
{
unsigned i;
size_t off = 0;
for (i = 0; i < cnt && off < len; i++)
off += csv_sscan_single(io, buf + off, len - off, smps[i]);
if (rbytes)
*rbytes = off;
return i;
}
void csv_header(struct io *io, const struct sample *smp)
{
FILE *f = io_stream_output(io);
fprintf(f, "# ");
if (io->flags & (int) SampleFlags::HAS_TS_ORIGIN)
fprintf(f, "secs%cnsecs%c", io->separator, io->separator);
if (io->flags & (int) SampleFlags::HAS_OFFSET)
fprintf(f, "offset%c", io->separator);
if (io->flags & (int) SampleFlags::HAS_SEQUENCE)
fprintf(f, "sequence%c", io->separator);
if (io->flags & (int) SampleFlags::HAS_DATA) {
for (unsigned i = 0; i < smp->length; i++) {
struct signal *sig = (struct signal *) vlist_at_safe(smp->signals, i);
if (!sig)
break;
if (sig->name)
fprintf(f, "%s", sig->name);
else
fprintf(f, "signal%u", i);
if (sig->unit)
fprintf(f, "[%s]", sig->unit);
if (i + 1 < smp->length)
fprintf(f, "%c", io->separator);
}
}
fprintf(f, "%c", io->delimiter);
}
static struct plugin p1;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p1.name = "tsv";
p1.description = "Tabulator-separated values";
p1.type = PluginType::FORMAT;
p1.format.header = csv_header;
p1.format.sprint = csv_sprint;
p1.format.sscan = csv_sscan;
p1.format.size = 0;
p1.format.flags = (int) IOFlags::NEWLINES |
(int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA;
p1.format.separator = '\t';
vlist_push(&plugins, &p1);
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p1);
}
static struct plugin p2;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p2.name = "csv";
p2.description = "Comma-separated values";
p2.type = PluginType::FORMAT;
p2.format.header = csv_header;
p2.format.sprint = csv_sprint;
p2.format.sscan = csv_sscan;
p2.format.size = 0;
p2.format.flags = (int) IOFlags::NEWLINES |
(int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA;
p2.format.separator = ',';
vlist_push(&plugins, &p2);
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p2);
}

View file

@ -24,20 +24,21 @@
#include <cstring>
#include <villas/plugin.h>
#include <villas/sample.h>
#include <villas/node.h>
#include <villas/signal.h>
#include <villas/compat.hpp>
#include <villas/timing.h>
#include <villas/io.h>
#include <villas/formats/json.h>
#include <villas/formats/iotagent_ul.hpp>
int iotagent_ul_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
using namespace villas;
using namespace villas::node;
int IotAgentUltraLightFormat::sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt)
{
size_t printed = 0;
struct signal *sig;
struct sample *smp = smps[0];
const struct sample *smp = smps[0];
for (unsigned i = 0; (i < smp->length) && (printed < len); i++) {
sig = (struct signal *) vlist_at_safe(smp->signals, i);
@ -59,18 +60,11 @@ int iotagent_ul_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, str
return 0;
}
static struct plugin p;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p.name = "iotagent_ul";
p.description = "FIWARE IotAgent UltraLight format";
p.type = PluginType::FORMAT;
p.format.sprint = iotagent_ul_sprint;
p.format.size = 0;
vlist_init_and_push(&plugins, &p);
int IotAgentUltraLightFormat::sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt)
{
return -1;
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p);
}
static char n[] = "iotagent_ul";
static char d[] = "FIWARE IotAgent UltraLight format";
static FormatPlugin<IotAgentUltraLightFormat, n, d, (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA> p;

View file

@ -20,17 +20,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <villas/plugin.h>
#include <villas/sample.h>
#include <villas/compat.hpp>
#include <villas/signal.h>
#include <villas/io.h>
#include <villas/formats/json.h>
#include <villas/formats/json.hpp>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
static enum SignalType json_detect_format(json_t *val)
enum SignalType JsonFormat::detect(const json_t *val)
{
int type = json_typeof(val);
@ -53,7 +52,7 @@ static enum SignalType json_detect_format(json_t *val)
}
}
static json_t * json_pack_timestamps(struct io *io, struct sample *smp)
json_t * JsonFormat::packTimestamps(const struct sample *smp)
{
json_t *json_ts = json_object();
@ -63,12 +62,12 @@ static json_t * json_pack_timestamps(struct io *io, struct sample *smp)
const char *fmt = "[ I, I ]";
#endif
if (io->flags & (int) SampleFlags::HAS_TS_ORIGIN) {
if (flags & (int) SampleFlags::HAS_TS_ORIGIN) {
if (smp->flags & (int) SampleFlags::HAS_TS_ORIGIN)
json_object_set(json_ts, "origin", json_pack(fmt, smp->ts.origin.tv_sec, smp->ts.origin.tv_nsec));
}
if (io->flags & (int) SampleFlags::HAS_TS_RECEIVED) {
if (flags & (int) SampleFlags::HAS_TS_RECEIVED) {
if (smp->flags & (int) SampleFlags::HAS_TS_RECEIVED)
json_object_set(json_ts, "received", json_pack(fmt, smp->ts.received.tv_sec, smp->ts.received.tv_nsec));
}
@ -76,7 +75,7 @@ static json_t * json_pack_timestamps(struct io *io, struct sample *smp)
return json_ts;
}
static int json_unpack_timestamps(json_t *json_ts, struct sample *smp)
int JsonFormat::unpackTimestamps(json_t *json_ts, struct sample *smp)
{
int ret;
json_error_t err;
@ -107,22 +106,22 @@ static int json_unpack_timestamps(json_t *json_ts, struct sample *smp)
return 0;
}
static int json_pack_sample(struct io *io, json_t **j, struct sample *smp)
int JsonFormat::packSample(json_t **json_smp, const struct sample *smp)
{
json_t *json_smp;
json_t *json_root;
json_error_t err;
json_smp = json_pack_ex(&err, 0, "{ s: o }", "ts", json_pack_timestamps(io, smp));
json_root = json_pack_ex(&err, 0, "{ s: o }", "ts", packTimestamps(smp));
if (io->flags & (int) SampleFlags::HAS_SEQUENCE) {
if (flags & (int) SampleFlags::HAS_SEQUENCE) {
if (smp->flags & (int) SampleFlags::HAS_SEQUENCE) {
json_t *json_sequence = json_integer(smp->sequence);
json_object_set(json_smp, "sequence", json_sequence);
json_object_set_new(json_root, "sequence", json_sequence);
}
}
if (io->flags & (int) SampleFlags::HAS_DATA) {
if (flags & (int) SampleFlags::HAS_DATA) {
json_t *json_data = json_array();
for (unsigned i = 0; i < smp->length; i++) {
@ -132,38 +131,38 @@ static int json_pack_sample(struct io *io, json_t **j, struct sample *smp)
json_t *json_value = signal_data_to_json(&smp->data[i], sig->type);
json_array_append(json_data, json_value);
json_array_append_new(json_data, json_value);
}
json_object_set(json_smp, "data", json_data);
json_object_set_new(json_root, "data", json_data);
}
*j = json_smp;
*json_smp = json_root;
return 0;
}
static int json_pack_samples(struct io *io, json_t **j, struct sample *smps[], unsigned cnt)
int JsonFormat::packSamples(json_t **json_smps, const struct sample * const smps[], unsigned cnt)
{
int ret;
json_t *json_smps = json_array();
json_t *json_root = json_array();
for (unsigned i = 0; i < cnt; i++) {
json_t *json_smp;
ret = json_pack_sample(io, &json_smp, smps[i]);
ret = packSample(&json_smp, smps[i]);
if (ret)
break;
json_array_append(json_smps, json_smp);
json_array_append_new(json_root, json_smp);
}
*j = json_smps;
*json_smps = json_root;
return cnt;
}
static int json_unpack_sample(struct io *io, json_t *json_smp, struct sample *smp)
int JsonFormat::unpackSample(json_t *json_smp, struct sample *smp)
{
int ret;
json_error_t err;
@ -171,7 +170,7 @@ static int json_unpack_sample(struct io *io, json_t *json_smp, struct sample *sm
size_t i;
int64_t sequence = -1;
smp->signals = io->signals;
smp->signals = signals;
ret = json_unpack_ex(json_smp, &err, 0, "{ s?: o, s?: I, s: o }",
"ts", &json_ts,
@ -184,7 +183,7 @@ static int json_unpack_sample(struct io *io, json_t *json_smp, struct sample *sm
smp->length = 0;
if (json_ts) {
ret = json_unpack_timestamps(json_ts, smp);
ret = unpackTimestamps(json_ts, smp);
if (ret)
return ret;
}
@ -205,7 +204,7 @@ static int json_unpack_sample(struct io *io, json_t *json_smp, struct sample *sm
if (!sig)
return -1;
enum SignalType fmt = json_detect_format(json_value);
enum SignalType fmt = detect(json_value);
if (sig->type != fmt)
throw RuntimeError("Received invalid data type in JSON payload: Received {}, expected {} for signal {} (index {}).",
signal_type_to_str(fmt), signal_type_to_str(sig->type), sig->name, i);
@ -223,7 +222,7 @@ static int json_unpack_sample(struct io *io, json_t *json_smp, struct sample *sm
return 0;
}
static int json_unpack_samples(struct io *io, json_t *json_smps, struct sample *smps[], unsigned cnt)
int JsonFormat::unpackSamples(json_t *json_smps, struct sample * const smps[], unsigned cnt)
{
int ret;
json_t *json_smp;
@ -236,7 +235,7 @@ static int json_unpack_samples(struct io *io, json_t *json_smps, struct sample *
if (i >= cnt)
break;
ret = json_unpack_sample(io, json_smp, smps[i]);
ret = unpackSample(json_smp, smps[i]);
if (ret < 0)
break;
}
@ -244,17 +243,17 @@ static int json_unpack_samples(struct io *io, json_t *json_smps, struct sample *
return i;
}
int json_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
int JsonFormat::sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt)
{
int ret;
json_t *json;
size_t wr;
ret = json_pack_samples(io, &json, smps, cnt);
ret = packSamples(&json, smps, cnt);
if (ret < 0)
return ret;
wr = json_dumpb(json, buf, len, 0);
wr = json_dumpb(json, buf, len, dump_flags);
json_decref(json);
@ -264,7 +263,7 @@ int json_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sam
return ret;
}
int json_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
int JsonFormat::sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt)
{
int ret;
json_t *json;
@ -274,7 +273,7 @@ int json_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struc
if (!json)
return -1;
ret = json_unpack_samples(io, json, smps, cnt);
ret = unpackSamples(json, smps, cnt);
json_decref(json);
@ -287,21 +286,19 @@ int json_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struc
return ret;
}
int json_print(struct io *io, struct sample *smps[], unsigned cnt)
int JsonFormat::print(FILE *f, const struct sample * const smps[], unsigned cnt)
{
int ret;
unsigned i;
json_t *json;
FILE *f = io_stream_output(io);
for (i = 0; i < cnt; i++) {
ret = json_pack_sample(io, &json, smps[i]);
ret = packSample(&json, smps[i]);
if (ret)
return ret;
ret = json_dumpf(json, f, 0);
fputc(io->delimiter, f);
ret = json_dumpf(json, f, dump_flags);
fputc('\n', f);
json_decref(json);
@ -312,15 +309,13 @@ int json_print(struct io *io, struct sample *smps[], unsigned cnt)
return i;
}
int json_scan(struct io *io, struct sample *smps[], unsigned cnt)
int JsonFormat::scan(FILE *f, struct sample * const smps[], unsigned cnt)
{
int ret;
unsigned i;
json_t *json;
json_error_t err;
FILE *f = io_stream_input(io);
for (i = 0; i < cnt; i++) {
if (feof(f))
return -1;
@ -329,7 +324,7 @@ skip: json = json_loadf(f, JSON_DISABLE_EOF_CHECK, &err);
if (!json)
break;
ret = json_unpack_sample(io, json, smps[i]);
ret = unpackSample(json, smps[i]);
if (ret)
goto skip;
@ -339,23 +334,54 @@ skip: json = json_loadf(f, JSON_DISABLE_EOF_CHECK, &err);
return i;
}
static struct plugin p;
void JsonFormat::parse(json_t *json)
{
int ret;
json_error_t err;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p.name = "json";
p.description = "Javascript Object Notation";
p.type = PluginType::FORMAT;
p.format.print = json_print;
p.format.scan = json_scan;
p.format.sprint = json_sprint;
p.format.sscan = json_sscan;
p.format.size = 0;
p.format.flags = (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA;
p.format.delimiter = '\n';
int indent = 0;
int compact = 0;
int ensure_ascii = 0;
int escape_slash = 0;
int sort_keys = 0;
vlist_init_and_push(&plugins, &p);
ret = json_unpack_ex(json, &err, 0, "{ s?: i, s?: b, s?: b, s?: b, s?: b }",
"indent", &indent,
"compact", &compact,
"ensure_ascii", &ensure_ascii,
"escape_slash", &escape_slash,
"sort_keys", &sort_keys
);
if (ret)
throw ConfigError(json, err, "node-config-format-json", "Failed to parse format configuration");
if (indent > JSON_MAX_INDENT)
throw ConfigError(json, "node-config-format-json-indent", "The maximum indentation level is {}", JSON_MAX_INDENT);
dump_flags = 0;
if (indent)
dump_flags |= JSON_INDENT(indent);
if (compact)
dump_flags |= JSON_COMPACT;
if (ensure_ascii)
dump_flags |= JSON_ENSURE_ASCII;
if (escape_slash)
dump_flags |= JSON_ESCAPE_SLASH;
if (sort_keys)
dump_flags |= JSON_SORT_KEYS;
Format::parse(json);
if (real_precision)
dump_flags |= JSON_REAL_PRECISION(real_precision);
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p);
}
static char n[] = "json";
static char d[] = "Javascript Object Notation";
static FormatPlugin<JsonFormat, n, d, (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA> p;

View file

@ -20,18 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <cstring>
#include <villas/plugin.h>
#include <villas/sample.h>
#include <villas/node.h>
#include <villas/signal.h>
#include <villas/compat.hpp>
#include <villas/timing.h>
#include <villas/io.h>
#include <villas/formats/json_kafka.h>
#include <villas/utils.hpp>
#include <villas/formats/json_kafka.hpp>
#include <villas/exceptions.hpp>
static const char * json_kafka_type_villas_to_kafka(enum SignalType vt)
using namespace villas;
using namespace villas::node;
const char * JsonKafkaFormat::villasToKafkaType(enum SignalType vt)
{
switch (vt) {
case SignalType::FLOAT:
@ -50,9 +47,9 @@ static const char * json_kafka_type_villas_to_kafka(enum SignalType vt)
}
}
static int json_kafka_pack_sample(struct io *io, json_t **json_smp, struct sample *smp)
int JsonKafkaFormat::packSample(json_t **json_smp, const struct sample *smp)
{
json_t *json_root, *json_schema, *json_payload, *json_fields, *json_field, *json_value;
json_t *json_payload, *json_fields, *json_field, *json_value;
json_fields = json_array();
json_payload = json_object();
@ -66,8 +63,8 @@ static int json_kafka_pack_sample(struct io *io, json_t **json_smp, struct sampl
);
uint64_t ts_origin_ms = smp->ts.origin.tv_sec * 1e3 + smp->ts.origin.tv_nsec / 1e6;
json_array_append(json_fields, json_field);
json_object_set(json_payload, "timestamp", json_integer(ts_origin_ms));
json_array_append_new(json_fields, json_field);
json_object_set_new(json_payload, "timestamp", json_integer(ts_origin_ms));
}
/* Include sample sequence no */
@ -78,44 +75,41 @@ static int json_kafka_pack_sample(struct io *io, json_t **json_smp, struct sampl
"field", "sequence"
);
json_array_append(json_fields, json_field);
json_object_set(json_payload, "sequence", json_integer(smp->sequence));
json_array_append_new(json_fields, json_field);
json_object_set_new(json_payload, "sequence", json_integer(smp->sequence));
}
/* Include sample data */
for (size_t i = 0; i < MIN(smp->length, vlist_length(smp->signals)); i++) {
struct signal *sig = (struct signal *) vlist_at(smp->signals, i);
union signal_data *data = &smp->data[i];
const union signal_data *data = &smp->data[i];
json_field = json_pack("{ s: s, s: b, s: s }",
"type", json_kafka_type_villas_to_kafka(sig->type),
"type", villasToKafkaType(sig->type),
"optional", false,
"field", sig->name
);
json_value = signal_data_to_json(data, sig->type);
json_array_append(json_fields, json_field);
json_object_set(json_payload, sig->name, json_value);
json_array_append_new(json_fields, json_field);
json_object_set_new(json_payload, sig->name, json_value);
}
json_schema = json_pack("{ s: s, s: s, s: o }",
"type", "struct",
"name", "villas-node.Value",
"fields", json_fields
);
json_object_set_new(json_schema, "fields", json_fields);
json_root = json_pack("{ s: o, s: o }",
json_incref(json_schema);
*json_smp = json_pack("{ s: o, s: o }",
"schema", json_schema,
"payload", json_payload
);
*json_smp = json_root;
);;
if (*json_smp == nullptr)
return -1;
return 0;
}
static int json_kafka_unpack_sample(struct io *io, json_t *json_smp, struct sample *smp)
int JsonKafkaFormat::unpackSample(json_t *json_smp, struct sample *smp)
{
json_t *json_payload, *json_value;
@ -125,7 +119,7 @@ static int json_kafka_unpack_sample(struct io *io, json_t *json_smp, struct samp
smp->length = 0;
smp->flags = 0;
smp->signals = io->signals;
smp->signals = signals;
/* Unpack timestamp */
json_value = json_object_get(json_payload, "timestamp");
@ -145,8 +139,8 @@ static int json_kafka_unpack_sample(struct io *io, json_t *json_smp, struct samp
}
/* Unpack signal data */
for (size_t i = 0; i < vlist_length(io->signals); i++) {
struct signal *sig = (struct signal *) vlist_at(io->signals, i);
for (size_t i = 0; i < vlist_length(signals); i++) {
struct signal *sig = (struct signal *) vlist_at(signals, i);
json_value = json_object_get(json_payload, sig->name);
if (!json_value)
@ -159,125 +153,44 @@ static int json_kafka_unpack_sample(struct io *io, json_t *json_smp, struct samp
if (smp->length > 0)
smp->flags |= (int) SampleFlags::HAS_DATA;
return 1;
return 0;
}
/*
* Note: The following functions are the same as io/json.c !!!
*/
int json_kafka_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
void JsonKafkaFormat::parse(json_t *json)
{
int ret;
json_t *json;
size_t wr;
assert(cnt == 1);
ret = json_kafka_pack_sample(io, &json, smps[0]);
if (ret < 0)
return ret;
wr = json_dumpb(json, buf, len, 0);
json_decref(json);
if (wbytes)
*wbytes = wr;
return ret;
}
int json_kafka_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
{
int ret;
json_t *json;
json_error_t err;
json_t *json_schema_tmp = nullptr;
assert(cnt == 1);
ret = json_unpack_ex(json, &err, 0, "{ s?: o }",
"schema", &json_schema_tmp
);
if (ret)
throw ConfigError(json, err, "node-config-format-json-kafka", "Failed to parse format configuration");
json = json_loadb(buf, len, 0, &err);
if (!json)
return -1;
if (json_schema_tmp) {
if (!json_is_object(json_schema_tmp))
throw ConfigError(json, "node-config-format-json-kafka-schema", "Kafka schema must be configured as a dictionary");
ret = json_kafka_unpack_sample(io, json, smps[0]);
if (json_schema)
json_decref(json_schema);
json_decref(json);
if (ret < 0)
return ret;
if (rbytes)
*rbytes = err.position;
return ret;
}
int json_kafka_print(struct io *io, struct sample *smps[], unsigned cnt)
{
int ret;
unsigned i;
json_t *json;
FILE *f = io_stream_output(io);
for (i = 0; i < cnt; i++) {
ret = json_kafka_pack_sample(io, &json, smps[i]);
if (ret)
return ret;
ret = json_dumpf(json, f, 0);
fputc('\n', f);
json_decref(json);
if (ret)
return ret;
json_schema = json_schema_tmp;
}
return i;
JsonFormat::parse(json);
}
int json_kafka_scan(struct io *io, struct sample *smps[], unsigned cnt)
JsonKafkaFormat::JsonKafkaFormat(int fl) :
JsonFormat(fl)
{
int ret;
unsigned i;
json_t *json;
json_error_t err;
FILE *f = io_stream_input(io);
for (i = 0; i < cnt; i++) {
skip: json = json_loadf(f, JSON_DISABLE_EOF_CHECK, &err);
if (!json)
break;
ret = json_kafka_unpack_sample(io, json, smps[i]);
json_decref(json);
if (ret < 0)
goto skip;
}
return i;
json_schema = json_pack("{ s: s, s: s }",
"type", "struct",
"name", "villas-node.Value"
);
}
static struct plugin p;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p.name = "json.kafka";
p.description = "JSON Kafka schema/payload messages";
p.type = PluginType::FORMAT;
p.format.print = json_kafka_print;
p.format.scan = json_kafka_scan;
p.format.sprint = json_kafka_sprint;
p.format.sscan = json_kafka_sscan;
p.format.size = 0;
vlist_init_and_push(&plugins, &p);
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p);
}
static char n[] = "json.kafka";
static char d[] = "JSON Kafka schema/payload messages";
static FormatPlugin<JsonKafkaFormat, n, d, (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA> p;

View file

@ -22,21 +22,21 @@
#include <cstring>
#include <villas/plugin.h>
#include <villas/sample.h>
#include <villas/node.h>
#include <villas/signal.h>
#include <villas/compat.hpp>
#include <villas/timing.h>
#include <villas/io.h>
#include <villas/formats/json_reserve.h>
#include <villas/formats/json_reserve.hpp>
using namespace villas::node;
#define JSON_RESERVE_INTEGER_TARGET 1
static int json_reserve_pack_sample(struct io *io, json_t **j, struct sample *smp)
int JsonReserveFormat::packSample(json_t **json_smp, const struct sample *smp)
{
json_error_t err;
json_t *json_data, *json_name, *json_unit, *json_value;
json_t *json_root;
json_t *json_data;
json_t *json_name;
json_t *json_unit;
json_t *json_value;
json_t *json_created = nullptr;
json_t *json_sequence = nullptr;
@ -75,24 +75,19 @@ static int json_reserve_pack_sample(struct io *io, json_t **j, struct sample *sm
continue;
if (json_unit)
json_object_set(json_value, "unit", json_unit);
json_object_set_new(json_value, "unit", json_unit);
if (json_created)
json_object_set(json_value, "created", json_created);
json_object_set_new(json_value, "created", json_created);
if (json_sequence)
json_object_set(json_value, "sequence", json_sequence);
json_object_set_new(json_value, "sequence", json_sequence);
json_array_append(json_data, json_value);
json_array_append_new(json_data, json_value);
}
if (json_created)
json_decref(json_created);
if (json_sequence)
json_decref(json_sequence);
*j = json_pack_ex(&err, 0, "{ s: o }",
json_root = json_pack_ex(&err, 0, "{ s: o }",
"measurements", json_data
);
if (*j == nullptr)
if (json_root == nullptr)
return -1;
#if 0
#ifdef JSON_RESERVE_INTEGER_TARGET
@ -106,18 +101,20 @@ static int json_reserve_pack_sample(struct io *io, json_t **j, struct sample *sm
if (endptr[0] != 0)
return -1;
json_object_set_new(*j, "target", json_integer(id));
json_object_set_new(json_root, "target", json_integer(id));
}
#else
if (io->out.node)
json_object_set_new(*j, "target", json_string(io->out.node->name));
json_object_set_new(json_root, "target", json_string(io->out.node->name));
#endif
#endif
*json_smp = json_root;
return 0;
}
static int json_reserve_unpack_sample(struct io *io, json_t *json_smp, struct sample *smp)
int JsonReserveFormat::unpackSample(json_t *json_smp, struct sample *smp)
{
int ret, idx;
double created = -1;
@ -185,12 +182,12 @@ static int json_reserve_unpack_sample(struct io *io, json_t *json_smp, struct sa
struct signal *sig;
sig = vlist_lookup_name<struct signal>(io->signals, name);
sig = vlist_lookup_name<struct signal>(signals, name);
if (sig) {
if (!sig->enabled)
continue;
idx = vlist_index(io->signals, sig);
idx = vlist_index(signals, sig);
}
else {
ret = sscanf(name, "signal_%d", &idx);
@ -220,122 +217,7 @@ static int json_reserve_unpack_sample(struct io *io, json_t *json_smp, struct sa
return smp->length > 0 ? 1 : 0;
}
/*
* Note: The following functions are the same as io/json.c !!!
*/
int json_reserve_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
{
int ret;
json_t *json;
size_t wr;
assert(cnt == 1);
ret = json_reserve_pack_sample(io, &json, smps[0]);
if (ret < 0)
return ret;
wr = json_dumpb(json, buf, len, 0);
json_decref(json);
if (wbytes)
*wbytes = wr;
return ret;
}
int json_reserve_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
{
int ret;
json_t *json;
json_error_t err;
assert(cnt == 1);
json = json_loadb(buf, len, 0, &err);
if (!json)
return -1;
ret = json_reserve_unpack_sample(io, json, smps[0]);
json_decref(json);
if (ret < 0)
return ret;
if (rbytes)
*rbytes = err.position;
return ret;
}
int json_reserve_print(struct io *io, struct sample *smps[], unsigned cnt)
{
int ret;
unsigned i;
json_t *json;
FILE *f = io_stream_output(io);
for (i = 0; i < cnt; i++) {
ret = json_reserve_pack_sample(io, &json, smps[i]);
if (ret)
return ret;
ret = json_dumpf(json, f, 0);
fputc('\n', f);
json_decref(json);
if (ret)
return ret;
}
return i;
}
int json_reserve_scan(struct io *io, struct sample *smps[], unsigned cnt)
{
int ret;
unsigned i;
json_t *json;
json_error_t err;
FILE *f = io_stream_input(io);
for (i = 0; i < cnt; i++) {
skip: json = json_loadf(f, JSON_DISABLE_EOF_CHECK, &err);
if (!json)
break;
ret = json_reserve_unpack_sample(io, json, smps[i]);
json_decref(json);
if (ret < 0)
goto skip;
}
return i;
}
static struct plugin p;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p.name = "json.reserve";
p.description = "RESERVE JSON format";
p.type = PluginType::FORMAT;
p.format.print = json_reserve_print;
p.format.scan = json_reserve_scan;
p.format.sprint = json_reserve_sprint;
p.format.sscan = json_reserve_sscan;
p.format.size = 0;
vlist_init_and_push(&plugins, &p);
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p);
}
static char n[] = "json.reserve";
static char d[] = "RESERVE JSON format";
static FormatPlugin<JsonReserveFormat, n, d, (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA> p;

169
lib/formats/line.cpp Normal file
View file

@ -0,0 +1,169 @@
/** Line-based formats
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <villas/formats/line.hpp>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
int LineFormat::sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt)
{
unsigned i;
size_t off = 0;
for (i = 0; i < cnt && off < len; i++)
off += sprintLine(buf + off, len - off, smps[i]);
if (wbytes)
*wbytes = off;
return i;
}
int LineFormat::sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt)
{
unsigned i;
size_t off = 0;
if (skip_first_line) {
if (!first_line_skipped) {
while (off < len) {
if (buf[off++] == delimiter)
break;
}
first_line_skipped = true;
}
}
for (i = 0; i < cnt && off < len; i++) {
/* Skip comment lines */
if (buf[off] == comment) {
while (off < len) {
if (buf[++off] == delimiter)
break;
}
if (off == len)
break;
}
off += sscanLine(buf + off, len - off, smps[i]);
}
if (rbytes)
*rbytes = off;
return i;
}
int LineFormat::print(FILE *f, const struct sample * const smps[], unsigned cnt)
{
int ret;
unsigned i;
if (cnt > 0 && smps[0]->signals)
header(f, smps[0]->signals);
for (i = 0; i < cnt; i++) {
size_t wbytes;
ret = sprint(out.buffer, out.buflen, &wbytes, &smps[i], 1);
if (ret < 0)
return ret;
fwrite(out.buffer, wbytes, 1, f);
}
return i;
}
int LineFormat::scan(FILE *f, struct sample * const smps[], unsigned cnt)
{
int ret;
unsigned i;
ssize_t bytes;
if (skip_first_line) {
if (!first_line_skipped) {
bytes = getdelim(&in.buffer, &in.buflen, delimiter, f);
if (bytes < 0)
return -1; /* An error or eof occured */
first_line_skipped = true;
}
}
for (i = 0; i < cnt; i++) {
size_t rbytes;
char *ptr;
skip: bytes = getdelim(&in.buffer, &in.buflen, delimiter, f);
if (bytes < 0)
return -1; /* An error or eof occured */
/* Skip whitespaces, empty and comment lines */
for (ptr = in.buffer; isspace(*ptr); ptr++);
if (ptr[0] == '\0' || ptr[0] == comment)
goto skip;
ret = sscan(in.buffer, bytes, &rbytes, &smps[i], 1);
if (ret < 0)
return ret;
}
return i;
}
void LineFormat::parse(json_t *json)
{
int ret;
json_error_t err;
const char *delim = nullptr;
int header = -1;
int skip = -1;
ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: b, s?: b }",
"delimiter", &delim,
"header", &header,
"skip_first_line", &skip
);
if (ret)
throw ConfigError(json, err, "node-config-format-line", "Failed to parse format configuration");
if (delim) {
if (strlen(delim) != 1)
throw ConfigError(json, "node-config-format-line-delimiter", "Line delimiter must be a single character!");
delimiter = delim[0];
}
if (header >= 0)
print_header = header;
if (skip >= 0)
skip_first_line = skip;
Format::parse(json);
}

View file

@ -22,8 +22,8 @@
#include <arpa/inet.h>
#include <villas/formats/msg.h>
#include <villas/formats/msg_format.h>
#include <villas/formats/msg.hpp>
#include <villas/formats/msg_format.hpp>
#include <villas/sample.h>
#include <villas/signal.h>
#include <villas/utils.hpp>
@ -61,7 +61,7 @@ void msg_hdr_ntoh(struct msg *m)
m->ts.nsec = ntohl(m->ts.nsec);
}
int msg_verify(struct msg *m)
int msg_verify(const struct msg *m)
{
if (m->version != MSG_VERSION)
return -1;
@ -73,7 +73,7 @@ int msg_verify(struct msg *m)
return 0;
}
int msg_to_sample(struct msg *msg, struct sample *smp, struct vlist *signals)
int msg_to_sample(const struct msg *msg, struct sample *smp, const struct vlist *sigs)
{
int ret;
unsigned i;
@ -83,8 +83,8 @@ int msg_to_sample(struct msg *msg, struct sample *smp, struct vlist *signals)
return ret;
unsigned len = MIN(msg->length, smp->capacity);
for (i = 0; i < MIN(len, vlist_length(signals)); i++) {
struct signal *sig = (struct signal *) vlist_at_safe(signals, i);
for (i = 0; i < MIN(len, vlist_length(sigs)); i++) {
struct signal *sig = (struct signal *) vlist_at_safe(sigs, i);
if (!sig)
return -1;
@ -110,7 +110,7 @@ int msg_to_sample(struct msg *msg, struct sample *smp, struct vlist *signals)
return 0;
}
int msg_from_sample(struct msg *msg_in, struct sample *smp, struct vlist *signals)
int msg_from_sample(struct msg *msg_in, const struct sample *smp, const struct vlist *sigs)
{
msg_in->type = MSG_TYPE_DATA;
msg_in->version = MSG_VERSION;
@ -122,7 +122,7 @@ int msg_from_sample(struct msg *msg_in, struct sample *smp, struct vlist *signal
msg_in->ts.nsec = smp->ts.origin.tv_nsec;
for (unsigned i = 0; i < smp->length; i++) {
struct signal *sig = (struct signal *) vlist_at_safe(signals, i);
struct signal *sig = (struct signal *) vlist_at_safe(sigs, i);
if (!sig)
return -1;

View file

@ -20,20 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
/* Generated message descriptors by protoc */
#include <villas.pb-c.h>
#include <villas/sample.h>
#include <villas/signal.h>
#include <villas/io.h>
#include <villas/plugin.h>
#include <villas/formats/protobuf.h>
#include <villas/formats/protobuf.hpp>
#include <villas/exceptions.hpp>
#include <villas/utils.hpp>
using namespace villas;
using namespace villas::utils;
using namespace villas::node;
static enum SignalType protobuf_detect_format(Villas__Node__Value *val)
enum SignalType ProtobufFormat::detect(const Villas__Node__Value *val)
{
switch (val->value_case) {
case VILLAS__NODE__VALUE__VALUE_F:
@ -54,7 +49,7 @@ static enum SignalType protobuf_detect_format(Villas__Node__Value *val)
}
}
int protobuf_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
int ProtobufFormat::sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt)
{
unsigned psz;
@ -76,16 +71,16 @@ int protobuf_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct
villas__node__sample__init(pb_smp);
struct sample *smp = smps[i];
const struct sample *smp = smps[i];
pb_smp->type = VILLAS__NODE__SAMPLE__TYPE__DATA;
if (io->flags & smp->flags & (int) SampleFlags::HAS_SEQUENCE) {
if (flags & smp->flags & (int) SampleFlags::HAS_SEQUENCE) {
pb_smp->has_sequence = 1;
pb_smp->sequence = smp->sequence;
}
if (io->flags & smp->flags & (int) SampleFlags::HAS_TS_ORIGIN) {
if (flags & smp->flags & (int) SampleFlags::HAS_TS_ORIGIN) {
pb_smp->timestamp = new Villas__Node__Timestamp;
if (!pb_smp->timestamp)
throw MemoryAllocationError();
@ -162,7 +157,7 @@ out:
return -1;
}
int protobuf_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
int ProtobufFormat::sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt)
{
unsigned i, j;
Villas__Node__Message *pb_msg;
@ -176,7 +171,7 @@ int protobuf_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, s
Villas__Node__Sample *pb_smp = pb_msg->samples[i];
smp->flags = 0;
smp->signals = io->signals;
smp->signals = signals;
if (pb_smp->type != VILLAS__NODE__SAMPLE__TYPE__DATA)
throw RuntimeError("Parsed non supported message type. Skipping");
@ -195,7 +190,7 @@ int protobuf_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, s
for (j = 0; j < MIN(pb_smp->n_values, smp->capacity); j++) {
Villas__Node__Value *pb_val = pb_smp->values[j];
enum SignalType fmt = protobuf_detect_format(pb_val);
enum SignalType fmt = detect(pb_val);
struct signal *sig = (struct signal *) vlist_at_safe(smp->signals, j);
if (!sig)
@ -240,21 +235,6 @@ int protobuf_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, s
return i;
}
static struct plugin p;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p.name = "protobuf";
p.description = "Google Protobuf";
p.type = PluginType::FORMAT;
p.format.sprint = protobuf_sprint;
p.format.sscan = protobuf_sscan;
p.format.flags = (int) IOFlags::HAS_BINARY_PAYLOAD |
(int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA;
vlist_init_and_push(&plugins, &p);
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p);
}
static char n[] = "protobuf";
static char d[] = "Google Protobuf";
static FormatPlugin<ProtobufFormat, n, d, (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA> p;

View file

@ -21,16 +21,18 @@
*********************************************************************************/
#include <villas/sample.h>
#include <villas/plugin.h>
#include <villas/utils.hpp>
#include <villas/io.h>
#include <villas/formats/raw.h>
#include <villas/formats/raw.hpp>
#include <villas/compat.hpp>
#include <villas/exceptions.hpp>
typedef float flt32_t;
typedef double flt64_t;
typedef long double flt128_t; /** @todo: check */
using namespace villas;
using namespace villas::node;
/** Convert double to host byte order */
#define SWAP_FLOAT_XTOH(o, b, n) ({ \
union { flt ## b ## _t f; uint ## b ## _t i; } x = { .f = n }; \
@ -51,7 +53,7 @@ typedef long double flt128_t; /** @todo: check */
/** Convert integer of varying width to big/little endian byte order */
#define SWAP_INT_HTOX(o, b, n) (o ? htobe ## b (n) : htole ## b (n))
int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
int RawFormat::sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt)
{
int o = 0;
size_t nlen;
@ -69,16 +71,14 @@ int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct samp
__float128 *f128 = (__float128 *) vbuf;
#endif
int bits = 1 << (io->flags >> 24);
for (unsigned i = 0; i < cnt; i++) {
struct sample *smp = smps[i];
const struct sample *smp = smps[i];
/* First three values are sequence, seconds and nano-seconds timestamps
*
* These fields are always encoded as integers!
*/
if (io->flags & RAW_FAKE_HEADER) {
if (fake) {
/* Check length */
nlen = (o + 3) * (bits / 8);
if (nlen >= len)
@ -92,28 +92,28 @@ int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct samp
break;
case 16:
i16[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 16, smp->sequence);
i16[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 16, smp->ts.origin.tv_sec);
i16[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 16, smp->ts.origin.tv_nsec);
i16[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 16, smp->sequence);
i16[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 16, smp->ts.origin.tv_sec);
i16[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 16, smp->ts.origin.tv_nsec);
break;
case 32:
i32[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 32, smp->sequence);
i32[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 32, smp->ts.origin.tv_sec);
i32[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 32, smp->ts.origin.tv_nsec);
i32[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 32, smp->sequence);
i32[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 32, smp->ts.origin.tv_sec);
i32[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 32, smp->ts.origin.tv_nsec);
break;
case 64:
i64[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 64, smp->sequence);
i64[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 64, smp->ts.origin.tv_sec);
i64[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 64, smp->ts.origin.tv_nsec);
i64[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 64, smp->sequence);
i64[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 64, smp->ts.origin.tv_sec);
i64[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 64, smp->ts.origin.tv_nsec);
break;
#ifdef HAS_128BIT
case 128:
i128[o++] = SWAP_INT_TO_LE(io->flags & RAW_BIG_ENDIAN, 128, smp->sequence);
i128[o++] = SWAP_INT_TO_LE(io->flags & RAW_BIG_ENDIAN, 128, smp->ts.origin.tv_sec);
i128[o++] = SWAP_INT_TO_LE(io->flags & RAW_BIG_ENDIAN, 128, smp->ts.origin.tv_nsec);
i128[o++] = SWAP_INT_TO_LE(endianess == Endianess::BIG, 128, smp->sequence);
i128[o++] = SWAP_INT_TO_LE(endianess == Endianess::BIG, 128, smp->ts.origin.tv_sec);
i128[o++] = SWAP_INT_TO_LE(endianess == Endianess::BIG, 128, smp->ts.origin.tv_nsec);
break;
#endif
}
@ -121,7 +121,7 @@ int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct samp
for (unsigned j = 0; j < smp->length; j++) {
enum SignalType fmt = sample_format(smp, j);
union signal_data *data = &smp->data[j];
const union signal_data *data = &smp->data[j];
/* Check length */
nlen = (o + (fmt == SignalType::COMPLEX ? 2 : 1)) * (bits / 8);
@ -140,15 +140,15 @@ int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct samp
break; /* Not supported */
case 32:
f32[o++] = SWAP_FLOAT_HTOX(io->flags & RAW_BIG_ENDIAN, 32, (float) data->f);
f32[o++] = SWAP_FLOAT_HTOX(endianess == Endianess::BIG, 32, (float) data->f);
break;
case 64:
f64[o++] = SWAP_FLOAT_HTOX(io->flags & RAW_BIG_ENDIAN, 64, data->f);
f64[o++] = SWAP_FLOAT_HTOX(endianess == Endianess::BIG, 64, data->f);
break;
#ifdef HAS_128BIT
case 128: f128[o++] = SWAP_FLOAT_HTOX(io->flags & RAW_BIG_ENDIAN, 128, data->f); break;
case 128: f128[o++] = SWAP_FLOAT_HTOX(endianess == Endianess::BIG, 128, data->f); break;
#endif
}
break;
@ -160,20 +160,20 @@ int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct samp
break;
case 16:
i16[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 16, data->i);
i16[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 16, data->i);
break;
case 32:
i32[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 32, data->i);
i32[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 32, data->i);
break;
case 64:
i64[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 64, data->i);
i64[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 64, data->i);
break;
#ifdef HAS_128BIT
case 128:
i128[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 128, data->i);
i128[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 128, data->i);
break;
#endif
}
@ -186,20 +186,20 @@ int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct samp
break;
case 16:
i16[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 16, data->b ? 1 : 0);
i16[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 16, data->b ? 1 : 0);
break;
case 32:
i32[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 32, data->b ? 1 : 0);
i32[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 32, data->b ? 1 : 0);
break;
case 64:
i64[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 64, data->b ? 1 : 0);
i64[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 64, data->b ? 1 : 0);
break;
#ifdef HAS_128BIT
case 128:
i128[o++] = SWAP_INT_HTOX(io->flags & RAW_BIG_ENDIAN, 128, data->b ? 1 : 0);
i128[o++] = SWAP_INT_HTOX(endianess == Endianess::BIG, 128, data->b ? 1 : 0);
break;
#endif
}
@ -218,18 +218,18 @@ int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct samp
break;
case 32:
f32[o++] = SWAP_FLOAT_HTOX(io->flags & RAW_BIG_ENDIAN, 32, (float) std::real(data->z));
f32[o++] = SWAP_FLOAT_HTOX(io->flags & RAW_BIG_ENDIAN, 32, (float) std::imag(data->z));
f32[o++] = SWAP_FLOAT_HTOX(endianess == Endianess::BIG, 32, (float) std::real(data->z));
f32[o++] = SWAP_FLOAT_HTOX(endianess == Endianess::BIG, 32, (float) std::imag(data->z));
break;
case 64:
f64[o++] = SWAP_FLOAT_HTOX(io->flags & RAW_BIG_ENDIAN, 64, std::real(data->z));
f64[o++] = SWAP_FLOAT_HTOX(io->flags & RAW_BIG_ENDIAN, 64, std::imag(data->z));
f64[o++] = SWAP_FLOAT_HTOX(endianess == Endianess::BIG, 64, std::real(data->z));
f64[o++] = SWAP_FLOAT_HTOX(endianess == Endianess::BIG, 64, std::imag(data->z));
break;
#ifdef HAS_128BIT
case 128:
f128[o++] = SWAP_FLOAT_HTOX(io->flags & RAW_BIG_ENDIAN, 128, std::real(data->z));
f128[o++] = SWAP_FLOAT_HTOX(io->flags & RAW_BIG_ENDIAN, 128, std::imag(data->z));
f128[o++] = SWAP_FLOAT_HTOX(endianess == Endianess::BIG, 128, std::real(data->z));
f128[o++] = SWAP_FLOAT_HTOX(endianess == Endianess::BIG, 128, std::imag(data->z));
break;
#endif
}
@ -247,7 +247,7 @@ out: if (wbytes)
return cnt;
}
int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
int RawFormat::sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt)
{
void *vbuf = (void *) buf; /* Avoid warning about invalid pointer cast */
@ -266,7 +266,7 @@ int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct
* as there is no support for framing. */
struct sample *smp = smps[0];
int o = 0, bits = 1 << (io->flags >> 24);
int o = 0;
int nlen = len / (bits / 8);
if (cnt > 1)
@ -275,7 +275,7 @@ int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct
if (len % (bits / 8))
return -1; /* Invalid RAW Payload length */
if (io->flags & RAW_FAKE_HEADER) {
if (fake) {
if (nlen < o + 3)
return -1; /* Received a packet with no fake header. Skipping... */
@ -287,28 +287,28 @@ int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct
break;
case 16:
smp->sequence = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 16, i16[o++]);
smp->ts.origin.tv_sec = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 16, i16[o++]);
smp->ts.origin.tv_nsec = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 16, i16[o++]);
smp->sequence = SWAP_INT_XTOH(endianess == Endianess::BIG, 16, i16[o++]);
smp->ts.origin.tv_sec = SWAP_INT_XTOH(endianess == Endianess::BIG, 16, i16[o++]);
smp->ts.origin.tv_nsec = SWAP_INT_XTOH(endianess == Endianess::BIG, 16, i16[o++]);
break;
case 32:
smp->sequence = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 32, i32[o++]);
smp->ts.origin.tv_sec = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 32, i32[o++]);
smp->ts.origin.tv_nsec = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 32, i32[o++]);
smp->sequence = SWAP_INT_XTOH(endianess == Endianess::BIG, 32, i32[o++]);
smp->ts.origin.tv_sec = SWAP_INT_XTOH(endianess == Endianess::BIG, 32, i32[o++]);
smp->ts.origin.tv_nsec = SWAP_INT_XTOH(endianess == Endianess::BIG, 32, i32[o++]);
break;
case 64:
smp->sequence = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 64, i64[o++]);
smp->ts.origin.tv_sec = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 64, i64[o++]);
smp->ts.origin.tv_nsec = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 64, i64[o++]);
smp->sequence = SWAP_INT_XTOH(endianess == Endianess::BIG, 64, i64[o++]);
smp->ts.origin.tv_sec = SWAP_INT_XTOH(endianess == Endianess::BIG, 64, i64[o++]);
smp->ts.origin.tv_nsec = SWAP_INT_XTOH(endianess == Endianess::BIG, 64, i64[o++]);
break;
#ifdef HAS_128BIT
case 128:
smp->sequence = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 128, i128[o++]);
smp->ts.origin.tv_sec = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 128, i128[o++]);
smp->ts.origin.tv_nsec = SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 128, i128[o++]);
smp->sequence = SWAP_INT_XTOH(endianess == Endianess::BIG, 128, i128[o++]);
smp->ts.origin.tv_sec = SWAP_INT_XTOH(endianess == Endianess::BIG, 128, i128[o++]);
smp->ts.origin.tv_nsec = SWAP_INT_XTOH(endianess == Endianess::BIG, 128, i128[o++]);
break;
#endif
}
@ -322,7 +322,7 @@ int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct
smp->ts.origin.tv_nsec = 0;
}
smp->signals = io->signals;
smp->signals = signals;
unsigned i;
for (i = 0; i < smp->capacity && o < nlen; i++) {
@ -335,10 +335,10 @@ int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct
case 8: data->f = -1; o++; break; /* Not supported */
case 16: data->f = -1; o++; break; /* Not supported */
case 32: data->f = SWAP_FLOAT_XTOH(io->flags & RAW_BIG_ENDIAN, 32, f32[o++]); break;
case 64: data->f = SWAP_FLOAT_XTOH(io->flags & RAW_BIG_ENDIAN, 64, f64[o++]); break;
case 32: data->f = SWAP_FLOAT_XTOH(endianess == Endianess::BIG, 32, f32[o++]); break;
case 64: data->f = SWAP_FLOAT_XTOH(endianess == Endianess::BIG, 64, f64[o++]); break;
#ifdef HAS_128BIT
case 128: data->f = SWAP_FLOAT_XTOH(io->flags & RAW_BIG_ENDIAN, 128, f128[o++]); break;
case 128: data->f = SWAP_FLOAT_XTOH(endianess == Endianess::BIG, 128, f128[o++]); break;
#endif
}
break;
@ -346,11 +346,11 @@ int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct
case SignalType::INTEGER:
switch (bits) {
case 8: data->i = (int8_t) i8[o++]; break;
case 16: data->i = (int16_t) SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 16, i16[o++]); break;
case 32: data->i = (int32_t) SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 32, i32[o++]); break;
case 64: data->i = (int64_t) SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 64, i64[o++]); break;
case 16: data->i = (int16_t) SWAP_INT_XTOH(endianess == Endianess::BIG, 16, i16[o++]); break;
case 32: data->i = (int32_t) SWAP_INT_XTOH(endianess == Endianess::BIG, 32, i32[o++]); break;
case 64: data->i = (int64_t) SWAP_INT_XTOH(endianess == Endianess::BIG, 64, i64[o++]); break;
#ifdef HAS_128BIT
case 128: data->i = (__int128) SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 128, i128[o++]); break;
case 128: data->i = (__int128) SWAP_INT_XTOH(endianess == Endianess::BIG, 128, i128[o++]); break;
#endif
}
break;
@ -358,11 +358,11 @@ int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct
case SignalType::BOOLEAN:
switch (bits) {
case 8: data->b = (bool) i8[o++]; break;
case 16: data->b = (bool) SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 16, i16[o++]); break;
case 32: data->b = (bool) SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 32, i32[o++]); break;
case 64: data->b = (bool) SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 64, i64[o++]); break;
case 16: data->b = (bool) SWAP_INT_XTOH(endianess == Endianess::BIG, 16, i16[o++]); break;
case 32: data->b = (bool) SWAP_INT_XTOH(endianess == Endianess::BIG, 32, i32[o++]); break;
case 64: data->b = (bool) SWAP_INT_XTOH(endianess == Endianess::BIG, 64, i64[o++]); break;
#ifdef HAS_128BIT
case 128: data->b = (bool) SWAP_INT_XTOH(io->flags & RAW_BIG_ENDIAN, 128, i128[o++]); break;
case 128: data->b = (bool) SWAP_INT_XTOH(endianess == Endianess::BIG, 128, i128[o++]); break;
#endif
}
break;
@ -373,20 +373,20 @@ int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct
case 16: data->z = std::complex<float>(-1, -1); o += 2; break; /* Not supported */
case 32: data->z = std::complex<float>(
SWAP_FLOAT_XTOH(io->flags & RAW_BIG_ENDIAN, 32, f32[o++]),
SWAP_FLOAT_XTOH(io->flags & RAW_BIG_ENDIAN, 32, f32[o++]));
SWAP_FLOAT_XTOH(endianess == Endianess::BIG, 32, f32[o++]),
SWAP_FLOAT_XTOH(endianess == Endianess::BIG, 32, f32[o++]));
break;
case 64: data->z = std::complex<float>(
SWAP_FLOAT_XTOH(io->flags & RAW_BIG_ENDIAN, 64, f64[o++]),
SWAP_FLOAT_XTOH(io->flags & RAW_BIG_ENDIAN, 64, f64[o++]));
SWAP_FLOAT_XTOH(endianess == Endianess::BIG, 64, f64[o++]),
SWAP_FLOAT_XTOH(endianess == Endianess::BIG, 64, f64[o++]));
break;
#if HAS_128BIT
case 128: data->z = std::complex<float>(
SWAP_FLOAT_XTOH(io->flags & RAW_BIG_ENDIAN, 128, f128[o++]),
SWAP_FLOAT_XTOH(io->flags & RAW_BIG_ENDIAN, 128, f128[o++]));
SWAP_FLOAT_XTOH(endianess == Endianess::BIG, 128, f128[o++]),
SWAP_FLOAT_XTOH(endianess == Endianess::BIG, 128, f128[o++]));
break;
#endif
}
@ -408,37 +408,50 @@ int raw_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct
return 1;
}
#define REGISTER_FORMAT_RAW(i, n, d, f) \
static struct plugin i; \
__attribute__((constructor(110))) static void UNIQUE(__ctor)() { \
i.name = n; \
i.description = d; \
i.type = PluginType::FORMAT; \
i.format.sprint = raw_sprint; \
i.format.sscan = raw_sscan; \
i.format.flags = f | (int) IOFlags::HAS_BINARY_PAYLOAD | \
(int) SampleFlags::HAS_DATA; \
\
vlist_push(&plugins, &i); \
} \
\
__attribute__((destructor(110))) static void UNIQUE(__dtor)() { \
vlist_remove_all(&plugins, &i); \
void RawFormat::parse(json_t *json)
{
int ret;
json_error_t err;
int fake_tmp = 0;
const char *end = nullptr;
ret = json_unpack_ex(json, &err, 0, "{ }",
"endianess", &end,
"fake", &fake_tmp,
"bits", &bits
);
if (ret)
throw ConfigError(json, err, "node-config-format-raw", "Failed to parse format configuration");
if (bits % 8 != 0 || bits > 128 || bits <= 0)
throw ConfigError(json, "node-config-format-raw-bits", "Failed to parse format configuration");
if (end) {
if (bits <= 8)
throw ConfigError(json, "node-config-format-raw-endianess", "An endianess settings must only provided for bits > 8");
if (!strcmp(end, "little"))
endianess = Endianess::LITTLE;
else if (!strcmp(end, "big"))
endianess = Endianess::BIG;
else
throw ConfigError(json, "node-config-format-raw-endianess", "Endianess must be either 'big' or 'little'");
}
fake = fake_tmp;
if (fake)
flags |= (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_TS_ORIGIN;
else
flags &= ~((int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_TS_ORIGIN);
BinaryFormat::parse(json);
}
/* Feel free to add additional format identifiers here to suit your needs */
REGISTER_FORMAT_RAW(p_8, "raw.8", "Raw 8 bit", RAW_BITS_8)
REGISTER_FORMAT_RAW(p_16be, "raw.16.be", "Raw 16 bit, big endian byte-order", RAW_BITS_16 | RAW_BIG_ENDIAN)
REGISTER_FORMAT_RAW(p_32be, "raw.32.be", "Raw 32 bit, big endian byte-order", RAW_BITS_32 | RAW_BIG_ENDIAN)
REGISTER_FORMAT_RAW(p_64be, "raw.64.be", "Raw 64 bit, big endian byte-order", RAW_BITS_64 | RAW_BIG_ENDIAN)
REGISTER_FORMAT_RAW(p_16le, "raw.16.le", "Raw 16 bit, little endian byte-order", RAW_BITS_16)
REGISTER_FORMAT_RAW(p_32le, "raw.32.le", "Raw 32 bit, little endian byte-order", RAW_BITS_32)
REGISTER_FORMAT_RAW(p_64le, "raw.64.le", "Raw 64 bit, little endian byte-order", RAW_BITS_64)
static char n1[] = "raw";
static char d1[] = "Raw binary data";
static FormatPlugin<RawFormat, n1, d1, (int) SampleFlags::HAS_DATA> p1;
#ifdef HAS_128BIT
REGISTER_FORMAT_RAW(p_128le, "raw.128.be", "Raw 128 bit, big endian byte-order", RAW_BITS_128 | RAW_BIG_ENDIAN)
REGISTER_FORMAT_RAW(p_128le, "raw.128.le", "Raw 128 bit, little endian byte-order", RAW_BITS_128)
#endif
REGISTER_FORMAT_RAW(p_gtnet, "gtnet", "RTDS GTNET", RAW_BITS_32 | RAW_BIG_ENDIAN)
REGISTER_FORMAT_RAW(p_gtnef, "gtnet.fake", "RTDS GTNET with fake header", RAW_BITS_32 | RAW_BIG_ENDIAN | RAW_FAKE_HEADER)
static char n2[] = "gtnet";
static char d2[] = "RTDS GTNET";
static FormatPlugin<GtnetRawFormat, n2, d2, (int) SampleFlags::HAS_DATA> p2;

View file

@ -20,20 +20,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <villas/io.h>
#include <villas/formats/csv.h>
#include <villas/plugin.h>
#include <villas/formats/value.hpp>
#include <villas/sample.h>
#include <villas/signal.h>
using namespace villas::utils;
using namespace villas::node;
int value_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
int ValueFormat::sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt)
{
unsigned i;
size_t off = 0;
struct signal *sig;
struct sample *smp = smps[0];
const struct sample *smp = smps[0];
assert(cnt == 1);
assert(smp->length <= 1);
@ -45,7 +43,7 @@ int value_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sa
if (!sig)
return -1;
off += signal_data_print_str(&smp->data[i], sig->type, buf, len);
off += signal_data_print_str(&smp->data[i], sig->type, buf, len, real_precision);
off += snprintf(buf + off, len - off, "\n");
}
@ -55,7 +53,7 @@ int value_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sa
return i;
}
int value_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
int ValueFormat::sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt)
{
unsigned i = 0, ret;
struct sample *smp = smps[0];
@ -68,7 +66,7 @@ int value_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, stru
printf("Reading: %s", buf);
if (smp->capacity >= 1) {
struct signal *sig = (struct signal *) vlist_at_safe(io->signals, i);
struct signal *sig = (struct signal *) vlist_at_safe(signals, i);
if (!sig)
return -1;
@ -81,7 +79,7 @@ int value_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, stru
}
out: smp->flags = 0;
smp->signals = io->signals;
smp->signals = signals;
smp->length = i;
if (smp->length > 0)
smp->flags |= (int) SampleFlags::HAS_DATA;
@ -92,21 +90,6 @@ out: smp->flags = 0;
return i;
}
static struct plugin p;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p.name = "value";
p.description = "A bare text value without any headers";
p.type = PluginType::FORMAT;
p.format.sprint = value_sprint;
p.format.sscan = value_sscan;
p.format.size = 0;
p.format.flags = (int) SampleFlags::HAS_DATA | (int) IOFlags::NEWLINES;
vlist_init_and_push(&plugins, &p);;
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
if (plugins.state != State::DESTROYED)
vlist_remove_all(&plugins, &p);
}
static char n[] = "value";
static char d[] = "A bare text value without any headers";
static FormatPlugin<ValueFormat, n, d, (int) SampleFlags::HAS_DATA> p;

View file

@ -21,16 +21,17 @@
*********************************************************************************/
#include <cstring>
#include <arpa/inet.h>
#include <villas/io.h>
#include <villas/formats/villas_binary.h>
#include <villas/formats/msg.h>
#include <villas/formats/msg_format.h>
#include <villas/formats/villas_binary.hpp>
#include <villas/formats/msg.hpp>
#include <villas/formats/msg_format.hpp>
#include <villas/sample.h>
#include <villas/utils.hpp>
#include <villas/plugin.h>
int villas_binary_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
using namespace villas::node;
int VillasBinaryFormat::sprint(char *buf, size_t len, size_t *wbytes, const struct sample * const smps[], unsigned cnt)
{
int ret;
unsigned i = 0;
@ -38,7 +39,7 @@ int villas_binary_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, s
for (i = 0; i < cnt; i++) {
struct msg *msg = (struct msg *) ptr;
struct sample *smp = smps[i];
const struct sample *smp = smps[i];
if (ptr + MSG_LEN(smp->length) > buf + len)
break;
@ -47,7 +48,7 @@ int villas_binary_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, s
if (ret)
return ret;
if (io->flags & VILLAS_BINARY_WEB) {
if (web) {
/** @todo convert to little endian */
}
else
@ -62,7 +63,7 @@ int villas_binary_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, s
return i;
}
int villas_binary_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
int VillasBinaryFormat::sscan(const char *buf, size_t len, size_t *rbytes, struct sample * const smps[], unsigned cnt)
{
int ret, values;
unsigned i = 0;
@ -75,7 +76,7 @@ int villas_binary_sscan(struct io *io, const char *buf, size_t len, size_t *rbyt
struct msg *msg = (struct msg *) ptr;
struct sample *smp = smps[i];
smp->signals = io->signals;
smp->signals = signals;
/* Complete buffer has been parsed */
if (ptr == buf + len)
@ -85,19 +86,19 @@ int villas_binary_sscan(struct io *io, const char *buf, size_t len, size_t *rbyt
if (ptr + sizeof(struct msg) > buf + len)
return -2; /* Invalid msg received */
values = (io->flags & VILLAS_BINARY_WEB) ? msg->length : ntohs(msg->length);
values = web ? msg->length : ntohs(msg->length);
/* Check if remainder of message is in buffer boundaries */
if (ptr + MSG_LEN(values) > buf + len)
return -3; /*Invalid msg receive */
if (io->flags & VILLAS_BINARY_WEB) {
if (web) {
/** @todo convert from little endian */
}
else
msg_ntoh(msg);
ret = msg_to_sample(msg, smp, io->signals);
ret = msg_to_sample(msg, smp, signals);
if (ret)
return ret; /* Invalid msg received */
@ -110,41 +111,5 @@ int villas_binary_sscan(struct io *io, const char *buf, size_t len, size_t *rbyt
return i;
}
static struct plugin p1;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p1.name = "villas.binary";
p1.description = "VILLAS binary network format";
p1.type = PluginType::FORMAT;
p1.format.sprint = villas_binary_sprint;
p1.format.sscan = villas_binary_sscan;
p1.format.size = 0;
p1.format.flags = (int) IOFlags::HAS_BINARY_PAYLOAD |
(int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA;
vlist_push(&plugins, &p1);
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p1);
}
/** The WebSocket node-type usually uses little endian byte order intead of network byte order */
static struct plugin p2;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p2.name = "villas.web";
p2.description = "VILLAS binary network format for WebSockets";
p2.type = PluginType::FORMAT;
p2.format.sprint = villas_binary_sprint;
p2.format.sscan = villas_binary_sscan;
p2.format.size = 0;
p2.format.flags = (int) IOFlags::HAS_BINARY_PAYLOAD | VILLAS_BINARY_WEB |
(int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA;
vlist_push(&plugins, &p2);
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p2);
}
static VillasBinaryFormatPlugin<false> p1;
static VillasBinaryFormatPlugin<true> p2;

View file

@ -23,20 +23,20 @@
#include <cinttypes>
#include <cstring>
#include <villas/io.h>
#include <villas/plugin.h>
#include <villas/utils.hpp>
#include <villas/timing.h>
#include <villas/sample.h>
#include <villas/signal.h>
#include <villas/formats/villas_human.h>
#include <villas/formats/villas_human.hpp>
static size_t villas_human_sprint_single(struct io *io, char *buf, size_t len, const struct sample *smp)
using namespace villas::node;
size_t VILLASHumanFormat::sprintLine(char *buf, size_t len, const struct sample *smp)
{
size_t off = 0;
struct signal *sig;
if (io->flags & (int) SampleFlags::HAS_TS_ORIGIN) {
if (flags & (int) SampleFlags::HAS_TS_ORIGIN) {
if (smp->flags & (int) SampleFlags::HAS_TS_ORIGIN) {
off += snprintf(buf + off, len - off, "%llu", (unsigned long long) smp->ts.origin.tv_sec);
off += snprintf(buf + off, len - off, ".%09llu", (unsigned long long) smp->ts.origin.tv_nsec);
@ -45,33 +45,33 @@ static size_t villas_human_sprint_single(struct io *io, char *buf, size_t len, c
off += snprintf(buf + off, len - off, "nan.nan");
}
if (io->flags & (int) SampleFlags::HAS_OFFSET) {
if (flags & (int) SampleFlags::HAS_OFFSET) {
if (smp->flags & (int) SampleFlags::HAS_TS_RECEIVED)
off += snprintf(buf + off, len - off, "%+e", time_delta(&smp->ts.origin, &smp->ts.received));
}
if (io->flags & (int) SampleFlags::HAS_SEQUENCE) {
if (flags & (int) SampleFlags::HAS_SEQUENCE) {
if (smp->flags & (int) SampleFlags::HAS_SEQUENCE)
off += snprintf(buf + off, len - off, "(%" PRIu64 ")", smp->sequence);
}
if (io->flags & (int) SampleFlags::HAS_DATA) {
if (flags & (int) SampleFlags::HAS_DATA) {
for (unsigned i = 0; i < smp->length; i++) {
sig = (struct signal *) vlist_at_safe(smp->signals, i);
if (!sig)
break;
off += snprintf(buf + off, len - off, "%c", io->separator);
off += signal_data_print_str(&smp->data[i], sig->type, buf + off, len - off);
off += snprintf(buf + off, len - off, "\t");
off += signal_data_print_str(&smp->data[i], sig->type, buf + off, len - off, real_precision);
}
}
off += snprintf(buf + off, len - off, "%c", io->delimiter);
off += snprintf(buf + off, len - off, "%c", delimiter);
return off;
}
static size_t villas_human_sscan_single(struct io *io, const char *buf, size_t len, struct sample *smp)
size_t VILLASHumanFormat::sscanLine(const char *buf, size_t len, struct sample *smp)
{
int ret;
char *end;
@ -80,7 +80,7 @@ static size_t villas_human_sscan_single(struct io *io, const char *buf, size_t l
double offset = 0;
smp->flags = 0;
smp->signals = io->signals;
smp->signals = signals;
/* Format: Seconds.NanoSeconds+Offset(SequenceNumber) Value1 Value2 ...
* RegEx: (\d+(?:\.\d+)?)([-+]\d+(?:\.\d+)?(?:e[+-]?\d+)?)?(?:\((\d+)\))?
@ -90,7 +90,7 @@ static size_t villas_human_sscan_single(struct io *io, const char *buf, size_t l
/* Mandatory: seconds */
smp->ts.origin.tv_sec = (uint32_t) strtoul(ptr, &end, 10);
if (ptr == end || *end == io->delimiter)
if (ptr == end || *end == delimiter)
return -1;
smp->flags |= (int) SampleFlags::HAS_TS_ORIGIN;
@ -133,10 +133,10 @@ static size_t villas_human_sscan_single(struct io *io, const char *buf, size_t l
unsigned i;
for (ptr = end + 1, i = 0; i < smp->capacity; ptr = end + 1, i++) {
if (*end == io->delimiter)
if (*end == delimiter)
goto out;
struct signal *sig = (struct signal *) vlist_at_safe(io->signals, i);
struct signal *sig = (struct signal *) vlist_at_safe(signals, i);
if (!sig)
goto out;
@ -145,7 +145,7 @@ static size_t villas_human_sscan_single(struct io *io, const char *buf, size_t l
goto out;
}
out: if (*end == io->delimiter)
out: if (*end == delimiter)
end++;
smp->length = i;
@ -162,84 +162,44 @@ out: if (*end == io->delimiter)
return end - buf;
}
int villas_human_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
void VILLASHumanFormat::header(FILE *f, const struct vlist *sigs)
{
unsigned i;
size_t off = 0;
for (i = 0; i < cnt && off < len; i++)
off += villas_human_sprint_single(io, buf + off, len - off, smps[i]);
if (wbytes)
*wbytes = off;
return i;
}
int villas_human_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
{
unsigned i;
size_t off = 0;
for (i = 0; i < cnt && off < len; i++)
off += villas_human_sscan_single(io, buf + off, len - off, smps[i]);
if (rbytes)
*rbytes = off;
return i;
}
void villas_human_header(struct io *io, const struct sample *smp)
{
FILE *f = io_stream_output(io);
/* Abort if we are not supposed to, or have already printed the header */
if (!print_header || header_printed)
return;
fprintf(f, "# ");
if (io->flags & (int) SampleFlags::HAS_TS_ORIGIN)
if (flags & (int) SampleFlags::HAS_TS_ORIGIN)
fprintf(f, "seconds.nanoseconds");
if (io->flags & (int) SampleFlags::HAS_OFFSET)
if (flags & (int) SampleFlags::HAS_OFFSET)
fprintf(f, "+offset");
if (io->flags & (int) SampleFlags::HAS_SEQUENCE)
if (flags & (int) SampleFlags::HAS_SEQUENCE)
fprintf(f, "(sequence)");
if (io->flags & (int) SampleFlags::HAS_DATA) {
for (unsigned i = 0; i < MIN(smp->length, vlist_length(smp->signals)); i++) {
struct signal *sig = (struct signal *) vlist_at_safe(smp->signals, i);
if (flags & (int) SampleFlags::HAS_DATA) {
for (unsigned i = 0; i < vlist_length(sigs); i++) {
struct signal *sig = (struct signal *) vlist_at_safe(sigs, i);
if (!sig)
break;
if (sig->name)
fprintf(f, "%c%s", io->separator, sig->name);
fprintf(f, "\t%s", sig->name);
else
fprintf(f, "%csignal%u", io->separator, i);
fprintf(f, "\tsignal%u", i);
if (sig->unit)
fprintf(f, "[%s]", sig->unit);
}
}
fprintf(f, "%c", io->delimiter);
fprintf(f, "%c", delimiter);
LineFormat::header(f, sigs);
}
static struct plugin p;
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {
p.name = "villas.human";
p.description = "VILLAS human readable format";
p.type = PluginType::FORMAT;
p.format.header = villas_human_header;
p.format.sprint = villas_human_sprint;
p.format.sscan = villas_human_sscan;
p.format.size = 0;
p.format.flags = (int) IOFlags::NEWLINES | (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA;
p.format.delimiter = '\n';
p.format.separator = '\t';
vlist_init_and_push(&plugins, &p);
}
__attribute__((destructor(110))) static void UNIQUE(__dtor)() {
vlist_remove_all(&plugins, &p);
}
static char n[] = "villas.human";
static char d[] = "VILLAS human readable format";
static LineFormatPlugin<VILLASHumanFormat, n, d, (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA, '\n'> p;

View file

@ -135,7 +135,7 @@ skip_add:
}
}
int hook_list_process(struct vlist *hs, struct sample *smps[], unsigned cnt)
int hook_list_process(struct vlist *hs, struct sample * smps[], unsigned cnt)
{
unsigned current, processed = 0;

View file

@ -33,7 +33,7 @@
#include <villas/hook.hpp>
#include <villas/path.h>
#include <villas/sample.h>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/plugin.h>
namespace villas {
@ -63,8 +63,6 @@ protected:
enum WindowType windowType;
enum PaddingType paddingType;
struct format_type *format;
std::vector<std::vector<double>> smpMemory;
std::vector<std::vector<std::complex<double>>> dftMatrix;
std::vector<std::complex<double>> dftResults;
@ -120,8 +118,6 @@ public:
lastDftCal({0, 0}),
signalIndex()
{
format = format_type_lookup("villas.human");
bool debug = false;
if (debug) {
origSigSync = std::make_shared<Dumper>("/tmp/plot/origSigSync");

View file

@ -24,12 +24,14 @@
* @{
*/
#include <cstdio>
#include <cstring>
#include <villas/node.h>
#include <villas/hook.hpp>
#include <villas/path.h>
#include <villas/sample.h>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/plugin.h>
namespace villas {
@ -38,85 +40,79 @@ namespace node {
class PrintHook : public Hook {
protected:
struct io io;
struct format_type *format;
Format *formatter;
FILE *stream;
char *prefix;
char *uri;
std::string prefix;
std::string uri;
public:
PrintHook(struct vpath *p, struct vnode *n, int fl, int prio, bool en = true) :
Hook(p, n, fl, prio, en),
io(),
prefix(nullptr),
uri(nullptr)
formatter(nullptr),
stream(nullptr)
{ }
virtual ~PrintHook()
{
format = format_type_lookup("villas.human");
if (formatter)
delete formatter;
}
virtual void start()
{
int ret;
assert(state == State::PREPARED || state == State::STOPPED);
ret = io_init(&io, format, &signals, (int) SampleFlags::HAS_ALL);
if (ret)
throw RuntimeError("Failed to initialze IO");
formatter->start(&signals);
ret = io_open(&io, uri);
if (ret)
throw RuntimeError("Failed to open IO");
stream = !uri.empty() ? fopen(uri.c_str(), "a+") : stdout;
if (!stream)
throw SystemError("Failed to open IO");
state = State::STARTED;
}
virtual void stop()
{
int ret;
assert(state == State::STARTED);
ret = io_close(&io);
if (ret)
throw RuntimeError("Failed to close IO");
ret = io_destroy(&io);
if (ret)
throw RuntimeError("Failed to destroy IO");
if (stream != stdout)
fclose(stream);
state = State::STOPPED;
}
virtual void parse(json_t *json)
{
const char *f = nullptr, *p = nullptr, *u = nullptr;
const char *p = nullptr, *u = nullptr;
int ret;
json_error_t err;
json_t *json_format = nullptr;
assert(state != State::STARTED);
Hook::parse(json);
ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: s, s?: s }",
ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: s, s?: o }",
"output", &u,
"prefix", &p,
"format", &f
"format", &json_format
);
if (ret)
throw ConfigError(json, err, "node-config-hook-print");
if (p)
prefix = strdup(p);
prefix = p;
if (u)
uri = strdup(u);
uri = u;
if (f) {
format = format_type_lookup(f);
if (!format)
throw ConfigError(json, "node-config-hook-print-format", "Invalid IO format '{}'", f);
}
/* Format */
formatter = json_format
? FormatFactory::make(json_format)
: FormatFactory::make("villas.human");
if (!formatter)
throw ConfigError(json_format, "node-config-hook-print-format", "Invalid format configuration");
state = State::PARSED;
}
@ -125,26 +121,19 @@ public:
{
assert(state == State::STARTED);
if (prefix)
printf("%s", prefix);
else if (node)
printf("Node %s: ", node_name(node));
else if (path)
printf("Path %s: ", path_name(path));
if (stream == stdout) {
if (!prefix.empty())
printf("%s", prefix.c_str());
else if (node)
printf("Node %s: ", node_name(node));
else if (path)
printf("Path %s: ", path_name(path));
}
io_print(&io, &smp, 1);
formatter->print(stream, smp);
return Reason::OK;
}
virtual ~PrintHook()
{
if (uri)
free(uri);
if (prefix)
free(prefix);
}
};
/* Register hook */

View file

@ -1,476 +0,0 @@
/** Reading and writing simulation samples in various formats.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, 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 <cstdlib>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <cctype>
#include <villas/io.h>
#include <villas/format_type.h>
#include <villas/utils.hpp>
#include <villas/sample.h>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::utils;
static int io_print_lines(struct io *io, struct sample *smps[], unsigned cnt)
{
int ret;
unsigned i;
FILE *f = io_stream_output(io);
for (i = 0; i < cnt; i++) {
size_t wbytes;
ret = io_sprint(io, io->out.buffer, io->out.buflen, &wbytes, &smps[i], 1);
if (ret < 0)
return ret;
fwrite(io->out.buffer, wbytes, 1, f);
}
return i;
}
static int io_scan_lines(struct io *io, struct sample *smps[], unsigned cnt)
{
int ret;
unsigned i;
FILE *f = io_stream_input(io);
for (i = 0; i < cnt; i++) {
size_t rbytes;
ssize_t bytes;
char *ptr;
skip: bytes = getdelim(&io->in.buffer, &io->in.buflen, io->delimiter, f);
if (bytes < 0)
return -1; /* An error or eof occured */
/* Skip whitespaces, empty and comment lines */
for (ptr = io->in.buffer; isspace(*ptr); ptr++);
if (ptr[0] == '\0' || ptr[0] == '#')
goto skip;
ret = io_sscan(io, io->in.buffer, bytes, &rbytes, &smps[i], 1);
if (ret < 0)
return ret;
}
return i;
}
int io_init(struct io *io, const struct format_type *fmt, struct vlist *signals, int flags)
{
int ret;
io->_vt = fmt;
io->_vd = new char[fmt->size];
if (!io->_vd)
throw MemoryAllocationError();
io->flags = flags | (io_type(io)->flags & ~(int) SampleFlags::HAS_ALL);
io->delimiter = io_type(io)->delimiter ? io_type(io)->delimiter : '\n';
io->separator = io_type(io)->separator ? io_type(io)->separator : '\t';
io->in.buflen =
io->out.buflen = 4096;
io->in.buffer = new char[io->in.buflen];
io->out.buffer = new char[io->out.buflen];
if (!io->in.buffer || !io->out.buffer)
throw MemoryAllocationError();
io->signals = signals;
ret = io_type(io)->init ? io_type(io)->init(io) : 0;
if (ret)
return ret;
io->state = State::INITIALIZED;
return 0;
}
int io_init2(struct io *io, const struct format_type *fmt, const char *dt, int flags)
{
int ret;
struct vlist *signals;
signals = new struct vlist;
if (!signals)
throw MemoryAllocationError();
ret = vlist_init(signals);
if (ret)
return ret;
ret = signal_list_generate2(signals, dt);
if (ret)
return ret;
flags |= (int) IOFlags::DESTROY_SIGNALS;
return io_init(io, fmt, signals, flags);
}
int io_destroy(struct io *io)
{
int ret;
assert(io->state == State::CLOSED || io->state == State::INITIALIZED);
ret = io_type(io)->destroy ? io_type(io)->destroy(io) : 0;
if (ret)
return ret;
delete[] (char *) io->_vd;
delete[] io->in.buffer;
delete[] io->out.buffer;
if (io->flags & (int) IOFlags::DESTROY_SIGNALS) {
ret = vlist_destroy(io->signals, (dtor_cb_t) signal_decref, false);
if (ret)
return ret;
}
return 0;
}
int io_stream_open(struct io *io, const char *uri)
{
int ret;
if (uri) {
if (!strcmp(uri, "-")) {
goto stdio;
}
else {
io->mode = IOMode::STDIO;
io->out.stream = fopen(uri, "a+");
if (io->out.stream == nullptr)
return -1;
io->in.stream = fopen(uri, "r");
if (io->in.stream == nullptr)
return -1;
}
}
else {
stdio: io->mode = IOMode::STDIO;
io->flags |= (int) IOFlags::FLUSH;
io->in.stream = stdin;
io->out.stream = stdout;
}
/* Make stream non-blocking if desired */
if (io->flags & (int) IOFlags::NONBLOCK) {
int ret, fd, flags;
fd = io_fd(io);
if (fd < 0)
return fd;
flags = fcntl(fd, F_GETFL);
if (flags < 0)
return flags;
flags |= O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if (ret)
return ret;
}
/* Enable line buffering on stdio */
if (io->mode == IOMode::STDIO) {
ret = setvbuf(io->in.stream, nullptr, _IOLBF, BUFSIZ);
if (ret)
return -1;
ret = setvbuf(io->out.stream, nullptr, _IOLBF, BUFSIZ);
if (ret)
return -1;
}
return 0;
}
int io_stream_close(struct io *io)
{
int ret;
switch (io->mode) {
case IOMode::STDIO:
if (io->in.stream == stdin)
return 0;
ret = fclose(io->in.stream);
if (ret)
return ret;
ret = fclose(io->out.stream);
if (ret)
return ret;
return 0;
case IOMode::CUSTOM:
return 0;
}
return -1;
}
int io_stream_flush(struct io *io)
{
switch (io->mode) {
case IOMode::STDIO:
return fflush(io->out.stream);
case IOMode::CUSTOM:
return 0;
}
return -1;
}
int io_stream_eof(struct io *io)
{
switch (io->mode) {
case IOMode::STDIO:
return feof(io->in.stream);
case IOMode::CUSTOM:
return 0;
}
return -1;
}
void io_stream_rewind(struct io *io)
{
switch (io->mode) {
case IOMode::STDIO:
rewind(io->in.stream);
break;
case IOMode::CUSTOM: { }
}
}
int io_stream_fd(struct io *io)
{
switch (io->mode) {
case IOMode::STDIO:
return fileno(io->in.stream);
case IOMode::CUSTOM:
return -1;
}
return -1;
}
int io_open(struct io *io, const char *uri)
{
int ret;
assert(io->state == State::INITIALIZED || io->state == State::CLOSED);
ret = io_type(io)->open
? io_type(io)->open(io, uri)
: io_stream_open(io, uri);
if (ret)
return ret;
io->header_printed = false;
io->state = State::OPENED;
return 0;
}
int io_close(struct io *io)
{
int ret;
assert(io->state == State::OPENED);
io_footer(io);
ret = io_type(io)->close
? io_type(io)->close(io)
: io_stream_close(io);
if (ret)
return ret;
io->state = State::CLOSED;
return 0;
}
int io_flush(struct io *io)
{
assert(io->state == State::OPENED);
return io_type(io)->flush
? io_type(io)->flush(io)
: io_stream_flush(io);
}
int io_eof(struct io *io)
{
assert(io->state == State::OPENED);
return io_type(io)->eof
? io_type(io)->eof(io)
: io_stream_eof(io);
}
void io_rewind(struct io *io)
{
assert(io->state == State::OPENED);
if (io_type(io)->rewind)
io_type(io)->rewind(io);
else
io_stream_rewind(io);
}
int io_fd(struct io *io)
{
assert(io->state == State::OPENED);
return io_type(io)->fd
? io_type(io)->fd(io)
: io_stream_fd(io);
}
const struct format_type * io_type(struct io *io)
{
return io->_vt;
}
void io_header(struct io *io, const struct sample *smp)
{
assert(io->state == State::OPENED);
if (io_type(io)->header)
io_type(io)->header(io, smp);
io->header_printed = true;
}
void io_footer(struct io *io)
{
assert(io->state == State::OPENED);
if (io_type(io)->footer)
io_type(io)->footer(io);
}
int io_print(struct io *io, struct sample *smps[], unsigned cnt)
{
int ret;
assert(io->state == State::OPENED);
if (!io->header_printed && cnt > 0)
io_header(io, smps[0]);
if (io->flags & (int) IOFlags::NEWLINES)
ret = io_print_lines(io, smps, cnt);
else if (io_type(io)->print)
ret = io_type(io)->print(io, smps, cnt);
else if (io_type(io)->sprint) {
FILE *f = io_stream_output(io);
size_t wbytes;
ret = io_sprint(io, io->out.buffer, io->out.buflen, &wbytes, smps, cnt);
fwrite(io->out.buffer, wbytes, 1, f);
}
else
ret = -1;
if (io->flags & (int) IOFlags::FLUSH)
io_flush(io);
return ret;
}
int io_scan(struct io *io, struct sample *smps[], unsigned cnt)
{
int ret;
assert(io->state == State::OPENED);
if (io->flags & (int) IOFlags::NEWLINES)
ret = io_scan_lines(io, smps, cnt);
else if (io_type(io)->scan)
ret = io_type(io)->scan(io, smps, cnt);
else if (io_type(io)->sscan) {
FILE *f = io_stream_input(io);
size_t bytes, rbytes;
bytes = fread(io->in.buffer, 1, io->in.buflen, f);
ret = io_sscan(io, io->in.buffer, bytes, &rbytes, smps, cnt);
}
else
ret = -1;
return ret;
}
FILE * io_stream_output(struct io *io) {
if (io->state != State::OPENED)
return 0;
return io->out.stream;
}
FILE * io_stream_input(struct io *io) {
if (io->state != State::OPENED)
return 0;
return io->in.stream;
}
int io_sscan(struct io *io, const char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt)
{
assert(io->state == State::INITIALIZED || io->state == State::OPENED || io->state == State::CLOSED);
return io_type(io)->sscan ? io_type(io)->sscan(io, buf, len, rbytes, smps, cnt) : -1;
}
int io_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt)
{
assert(io->state == State::INITIALIZED || io->state == State::OPENED || io->state == State::CLOSED);
return io_type(io)->sprint ? io_type(io)->sprint(io, buf, len, wbytes, smps, cnt) : -1;
}

View file

@ -69,7 +69,6 @@ int node_init(struct vnode *n, struct vnode_type *vt)
uuid_clear(n->uuid);
n->output_path = nullptr;
n->name = nullptr;
n->_name = nullptr;
n->_name_long = nullptr;
@ -444,7 +443,7 @@ int node_destroy(struct vnode *n)
return 0;
}
int node_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int node_read(struct vnode *n, struct sample * smps[], unsigned cnt)
{
int toread, readd, nread = 0;
unsigned vect;
@ -462,7 +461,7 @@ int node_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *re
while (cnt - nread > 0) {
toread = MIN(cnt - nread, vect);
readd = node_type(n)->read(n, &smps[nread], toread, release);
readd = node_type(n)->read(n, &smps[nread], toread);
if (readd < 0)
return readd;
@ -494,7 +493,7 @@ int node_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *re
#endif /* WITH_HOOKS */
}
int node_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int node_write(struct vnode *n, struct sample * smps[], unsigned cnt)
{
int tosend, sent, nsent = 0;
unsigned vect;
@ -519,7 +518,7 @@ int node_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *r
while (cnt - nsent > 0) {
tosend = MIN(cnt - nsent, vect);
sent = node_type(n)->write(n, &smps[nsent], tosend, release);
sent = node_type(n)->write(n, &smps[nsent], tosend);
if (sent < 0)
return sent;
@ -558,8 +557,8 @@ char * node_name_long(struct vnode *n)
strcatf(&n->_name_long, ", fwmark=%d", n->fwmark);
#endif /* WITH_NETEM */
if (n->output_path)
strcatf(&n->_name_long, ", output_path=%s", path_name(n->output_path));
if (n->out.path)
strcatf(&n->_name_long, ", out.path=%s", path_name(n->out.path));
if (node_type(n)->print) {
struct vnode_type *vt = node_type(n);
@ -675,8 +674,8 @@ struct vlist * node_input_signals(struct vnode *n)
struct vlist * node_output_signals(struct vnode *n)
{
if (n->output_path)
return path_output_signals(n->output_path);
if (n->out.path)
return path_output_signals(n->out.path);
return nullptr;
}

View file

@ -57,6 +57,7 @@ int node_direction_init(struct vnode_direction *nd, enum NodeDir dir, struct vno
nd->enabled = 1;
nd->vectorize = 1;
nd->builtin = 1;
nd->path = nullptr;
#ifdef WITH_HOOKS
ret = hook_list_init(&nd->hooks);

View file

@ -28,10 +28,10 @@
#include <villas/plugin.h>
#include <villas/nodes/amqp.hpp>
#include <villas/utils.hpp>
#include <villas/format_type.h>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
static void amqp_default_ssl_info(struct amqp_ssl_info *s)
@ -121,7 +121,6 @@ int amqp_parse(struct vnode *n, json_t *json)
struct amqp *a = (struct amqp *) n->_vd;
int port = 5672;
const char *format = "json";
const char *uri = nullptr;
const char *host = "localhost";
const char *vhost = "/";
@ -132,12 +131,13 @@ int amqp_parse(struct vnode *n, json_t *json)
json_error_t err;
json_t *json_ssl = nullptr;
json_t *json_format = nullptr;
/* Default values */
amqp_default_ssl_info(&a->ssl_info);
amqp_default_connection_info(&a->connection_info);
ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: s, s?: s, s?: s, s?: s, s?: i, s: s, s: s, s?: s, s?: o }",
ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: s, s?: s, s?: s, s?: s, s?: i, s: s, s: s, s?: o, s?: o }",
"uri", &uri,
"host", &host,
"vhost", &vhost,
@ -146,7 +146,7 @@ int amqp_parse(struct vnode *n, json_t *json)
"port", &port,
"exchange", &exchange,
"routing_key", &routing_key,
"format", &format,
"format", &json_format,
"ssl", &json_ssl
);
if (ret)
@ -189,9 +189,12 @@ int amqp_parse(struct vnode *n, json_t *json)
a->ssl_info.client_key = strdup(client_key);
}
a->format = format_type_lookup(format);
if (!a->format)
throw ConfigError(json, "node-config-node-amqp-format", "Invalid format '{}'", format);
/* Format */
a->formatter = json_format
? FormatFactory::make(json_format)
: FormatFactory::make("json");
if (!a->formatter)
throw ConfigError(json_format, "node-config-node-amqp-format", "Invalid format configuration");
return 0;
}
@ -202,8 +205,7 @@ char * amqp_print(struct vnode *n)
char *buf = nullptr;
strcatf(&buf, "format=%s, uri=%s://%s:%s@%s:%d%s, exchange=%s, routing_key=%s",
format_type_name(a->format),
strcatf(&buf, "uri=%s://%s:%s@%s:%d%s, exchange=%s, routing_key=%s",
a->connection_info.ssl ? "amqps" : "amqp",
a->connection_info.user,
a->connection_info.password,
@ -235,16 +237,13 @@ char * amqp_print(struct vnode *n)
int amqp_start(struct vnode *n)
{
int ret;
struct amqp *a = (struct amqp *) n->_vd;
amqp_bytes_t queue;
amqp_rpc_reply_t rep;
amqp_queue_declare_ok_t *r;
ret = io_init(&a->io, a->format, &n->in.signals, (int) SampleFlags::HAS_ALL & ~(int) SampleFlags::HAS_OFFSET);
if (ret)
return ret;
a->formatter->start(&n->in.signals, ~(int) SampleFlags::HAS_OFFSET);
/* Connect producer */
a->producer = amqp_connect(&a->connection_info, &a->ssl_info);
@ -302,14 +301,12 @@ int amqp_stop(struct vnode *n)
if (ret)
return ret;
ret = io_destroy(&a->io);
if (ret)
return ret;
delete a->formatter;
return 0;
}
int amqp_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int amqp_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret;
struct amqp *a = (struct amqp *) n->_vd;
@ -320,21 +317,21 @@ int amqp_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *re
if (rep.reply_type != AMQP_RESPONSE_NORMAL)
return -1;
ret = io_sscan(&a->io, static_cast<char *>(env.message.body.bytes), env.message.body.len, nullptr, smps, cnt);
ret = a->formatter->sscan(static_cast<char *>(env.message.body.bytes), env.message.body.len, nullptr, smps, cnt);
amqp_destroy_envelope(&env);
return ret;
}
int amqp_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int amqp_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret;
struct amqp *a = (struct amqp *) n->_vd;
char data[1500];
size_t wbytes;
ret = io_sprint(&a->io, data, sizeof(data), &wbytes, smps, cnt);
ret = a->formatter->sprint(data, sizeof(data), &wbytes, smps, cnt);
if (ret <= 0)
return -1;

View file

@ -84,7 +84,7 @@ int can_destroy(struct vnode *n)
return 0;
}
int can_parse_signal(json_t *json, struct vlist *node_signals, struct can_signal *can_signals, size_t signal_index)
static int can_parse_signal(json_t *json, struct vlist *node_signals, struct can_signal *can_signals, size_t signal_index)
{
const char *name = nullptr;
uint64_t can_id = 0;
@ -243,7 +243,7 @@ int can_stop(struct vnode *n)
return 0;
}
int can_conv_to_raw(union signal_data* sig, struct signal *from, void* to, int size)
static int can_convert_to_raw(const union signal_data *sig, const struct signal *from, void *to, int size)
{
if (size <= 0 || size > 8)
throw RuntimeError("Signal size cannot be larger than 8!");
@ -261,7 +261,6 @@ int can_conv_to_raw(union signal_data* sig, struct signal *from, void* to, int s
case 2:
*(int16_t*)to = (int16_t)sig->i;
sig->i = (int64_t)*(int16_t*)from;
return 0;
case 3:
@ -377,7 +376,7 @@ fail:
return 1;
}
int can_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int can_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret = 0;
int nbytes;
@ -446,7 +445,7 @@ int can_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *rel
return ret;
}
int can_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int can_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int nbytes;
unsigned nwrite;
@ -467,7 +466,7 @@ int can_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *re
frame[fsize].can_dlc = c->out[i].size;
frame[fsize].can_id = c->out[i].id;
can_conv_to_raw(
can_convert_to_raw(
&smps[nwrite]->data[i],
(struct signal*)vlist_at(&(n->out.signals), i),
&frame[fsize].data,
@ -486,7 +485,7 @@ int can_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *re
continue;
frame[j].can_dlc += c->out[i].size;
can_conv_to_raw(
can_convert_to_raw(
&smps[nwrite]->data[i],
(struct signal*)vlist_at(&(n->out.signals), i),
(uint8_t*)&frame[j].data + c->out[i].offset,

View file

@ -33,6 +33,7 @@
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
/* Utility functions to dump a comedi_cmd graciously taken from comedilib demo */
@ -510,7 +511,7 @@ int comedi_stop(struct vnode *n)
#if COMEDI_USE_READ
int comedi_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int comedi_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret;
struct comedi *c = (struct comedi *) n->_vd;
@ -622,7 +623,7 @@ int comedi_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *
#else
int comedi_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int comedi_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret;
struct comedi *c = (struct comedi *) n->_vd;
@ -800,7 +801,7 @@ int comedi_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *
#endif
int comedi_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int comedi_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret;
struct comedi *c = (struct comedi *) n->_vd;
@ -858,7 +859,7 @@ int comedi_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned
size_t villas_samples_written = 0;
while (villas_samples_written < cnt) {
struct sample *sample = smps[villas_samples_written];
const struct sample *sample = smps[villas_samples_written];
if (sample->length != d->chanlist_len)
throw RuntimeError("Value count in sample ({}) != configured output channels ({})", sample->length, d->chanlist_len);

View file

@ -31,6 +31,7 @@
#include <villas/nodes/ethercat.hpp>
using namespace villas;
using namespace villas::node;
/* Forward declartions */
static struct plugin p;
@ -320,7 +321,7 @@ int ethercat_stop(struct vnode *n)
return 0;
}
int ethercat_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int ethercat_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct ethercat *w = (struct ethercat *) n->_vd;
@ -337,7 +338,7 @@ int ethercat_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned
return avail;
}
int ethercat_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int ethercat_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct ethercat *w = (struct ethercat *) n->_vd;

View file

@ -168,7 +168,7 @@ int example_resume(struct vnode *n)
return 0;
}
int example_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int example_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int read;
struct example *s = (struct example *) n->_vd;
@ -192,7 +192,7 @@ int example_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned
return read;
}
int example_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int example_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int written;
//struct example *s = (struct example *) n->_vd;

View file

@ -29,6 +29,7 @@
#include <villas/node/exceptions.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
int exec_parse(struct vnode *n, json_t *json)
@ -40,14 +41,14 @@ int exec_parse(struct vnode *n, json_t *json)
json_t *json_exec;
json_t *json_env = nullptr;
json_t *json_format = nullptr;
const char *wd = nullptr;
const char *format = "villas.human";
int shell = -1;
ret = json_unpack_ex(json, &err, 0, "{ s: o, s?: s, s?: b, s?: o, s?: b, s?: s }",
ret = json_unpack_ex(json, &err, 0, "{ s: o, s?: o, s?: b, s?: o, s?: b, s?: s }",
"exec", &json_exec,
"format", &format,
"format", &json_format,
"flush", &flush,
"environment", &json_env,
"shell", &shell,
@ -101,26 +102,25 @@ int exec_parse(struct vnode *n, json_t *json)
}
}
json_t *json_format = json_object_get(json, "format");
e->format = format_type_lookup(format);
if (!e->format)
throw ConfigError(json_format, "node-config-node-exec-format", "Invalid format: {)", format);
/* Format */
e->formatter = json_format
? FormatFactory::make(json_format)
: FormatFactory::make("villas.human");
if (!e->formatter)
throw ConfigError(json_format, "node-config-node-exec-format", "Invalid format configuration");
if (!(e->format->flags & (int) IOFlags::NEWLINES))
throw ConfigError(json_format, "node-config-node-exec-format", "Only line-delimited formats are currently supported");
// if (!(e->format->flags & (int) Flags::NEWLINES))
// throw ConfigError(json_format, "node-config-node-exec-format", "Only line-delimited formats are currently supported");
return 0;
}
int exec_prepare(struct vnode *n)
{
int ret;
struct exec *e = (struct exec *) n->_vd;
/* Initialize IO */
ret = io_init(&e->io, e->format, &n->in.signals, (int) SampleFlags::HAS_ALL);
if (ret)
return ret;
e->formatter->start(&n->in.signals);
/* Start subprocess */
e->proc = std::make_unique<Popen>(e->command, e->arguments, e->environment, e->working_dir, e->shell);
@ -144,14 +144,9 @@ int exec_init(struct vnode *n)
int exec_destroy(struct vnode *n)
{
int ret;
struct exec *e = (struct exec *) n->_vd;
if (e->io.state == State::INITIALIZED) {
ret = io_destroy(&e->io);
if (ret)
return ret;
}
delete e->formatter;
using uptr = std::unique_ptr<Popen>;
using str = std::string;
@ -182,7 +177,7 @@ int exec_stop(struct vnode *n)
return 0;
}
int exec_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int exec_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct exec *e = (struct exec *) n->_vd;
@ -192,14 +187,14 @@ int exec_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *re
std::getline(e->proc->cin(), line);
avail = io_sscan(&e->io, line.c_str(), line.length(), &rbytes, smps, cnt);
avail = e->formatter->sscan(line.c_str(), line.length(), &rbytes, smps, cnt);
if (rbytes - 1 != line.length())
return -1;
return avail;
}
int exec_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int exec_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct exec *e = (struct exec *) n->_vd;
@ -209,7 +204,7 @@ int exec_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *r
if (!line)
throw MemoryAllocationError();
ret = io_sprint(&e->io, line, 1024, &wbytes, smps, cnt);
ret = e->formatter->sprint(line, 1024, &wbytes, smps, cnt);
if (ret < 0)
return ret;
@ -228,8 +223,7 @@ char * exec_print(struct vnode *n)
struct exec *e = (struct exec *) n->_vd;
char *buf = nullptr;
strcatf(&buf, "format=%s, exec=%s, shell=%s, flush=%s, #environment=%zu, #arguments=%zu, working_dir=%s",
format_type_name(e->format),
strcatf(&buf, "exec=%s, shell=%s, flush=%s, #environment=%zu, #arguments=%zu, working_dir=%s",
e->command.c_str(),
e->shell ? "yes" : "no",
e->flush ? "yes" : "no",

View file

@ -32,10 +32,11 @@
#include <villas/timing.h>
#include <villas/queue.h>
#include <villas/plugin.h>
#include <villas/io.h>
#include <villas/format.hpp>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
static char * file_format_name(const char *format, struct timespec *ts)
@ -86,16 +87,16 @@ int file_parse(struct vnode *n, json_t *json)
int ret;
json_error_t err;
json_t *json_format;
const char *uri_tmpl = nullptr;
const char *format = "villas.human";
const char *eof = nullptr;
const char *epoch = nullptr;
double epoch_flt = 0;
ret = json_unpack_ex(json, &err, 0, "{ s: s, s?: s, s?: { s?: s, s?: F, s?: s, s?: F, s?: i, s?: i }, s?: { s?: b, s?: i } }",
ret = json_unpack_ex(json, &err, 0, "{ s: s, s?: o, s?: { s?: s, s?: F, s?: s, s?: F, s?: i, s?: i }, s?: { s?: b, s?: i } }",
"uri", &uri_tmpl,
"format", &format,
"format", &json_format,
"in",
"eof", &eof,
"rate", &f->rate,
@ -113,9 +114,12 @@ int file_parse(struct vnode *n, json_t *json)
f->epoch = time_from_double(epoch_flt);
f->uri_tmpl = uri_tmpl ? strdup(uri_tmpl) : nullptr;
f->format = format_type_lookup(format);
if (!f->format)
throw RuntimeError("Invalid format '{}'", format);
/* Format */
f->formatter = json_format
? FormatFactory::make(json_format)
: FormatFactory::make("villas.human");
if (!f->formatter)
throw ConfigError(json_format, "node-config-node-file-format", "Invalid format configuration");
if (eof) {
if (!strcmp(eof, "exit") || !strcmp(eof, "stop"))
@ -200,9 +204,8 @@ char * file_print(struct vnode *n)
break;
}
strcatf(&buf, "uri=%s, format=%s, out.flush=%s, in.skip=%d, in.eof=%s, in.epoch=%s, in.epoch=%.2f",
strcatf(&buf, "uri=%s, out.flush=%s, in.skip=%d, in.eof=%s, in.epoch=%s, in.epoch=%.2f",
f->uri ? f->uri : f->uri_tmpl,
format_type_name(f->format),
f->flush ? "yes" : "no",
f->skip_lines,
eof_str,
@ -238,7 +241,7 @@ int file_start(struct vnode *n)
struct file *f = (struct file *) n->_vd;
struct timespec now = time_now();
int ret, flags;
int ret;
/* Prepare file name */
f->uri = file_format_name(f->uri_tmpl, &now);
@ -266,28 +269,26 @@ int file_start(struct vnode *n)
free(cpy);
/* Open file */
flags = (int) SampleFlags::HAS_ALL;
if (f->flush)
flags |= (int) IOFlags::FLUSH;
ret = io_init(&f->io, f->format, &n->in.signals, flags);
if (ret)
return ret;
f->formatter->start(&n->in.signals);
ret = io_open(&f->io, f->uri);
if (ret)
return ret;
f->stream_in = fopen(f->uri, "r");
if (!f->stream_in)
return -1;
f->stream_out = fopen(f->uri, "a+");
if (!f->stream_out)
return -1;
if (f->buffer_size_in) {
ret = setvbuf(f->io.in.stream, nullptr, _IOFBF, f->buffer_size_in);
ret = setvbuf(f->stream_in, nullptr, _IOFBF, f->buffer_size_in);
if (ret)
return ret;
}
if (f->buffer_size_out) {
ret = setvbuf(f->io.out.stream, nullptr, _IOFBF, f->buffer_size_out);
ret = setvbuf(f->stream_out, nullptr, _IOFBF, f->buffer_size_out);
if (ret)
return ret;
}
@ -297,20 +298,19 @@ int file_start(struct vnode *n)
/* Get timestamp of first line */
if (f->epoch_mode != file::EpochMode::ORIGINAL) {
io_rewind(&f->io);
rewind(f->stream_in);
if (io_eof(&f->io)) {
if (feof(f->stream_in)) {
n->logger->warn("Empty file");
}
else {
struct sample s;
struct sample *smps[] = { &s };
struct sample smp;
s.capacity = 0;
smp.capacity = 0;
ret = io_scan(&f->io, smps, 1);
ret = f->formatter->scan(f->stream_in, &smp);
if (ret == 1) {
f->first = s.ts.origin;
f->first = smp.ts.origin;
f->offset = file_calc_offset(&f->first, &f->epoch, f->epoch_mode);
}
else
@ -318,12 +318,12 @@ int file_start(struct vnode *n)
}
}
io_rewind(&f->io);
rewind(f->stream_in);
/* Fast-forward */
struct sample *smp = sample_alloc_mem(vlist_length(&n->in.signals));
for (unsigned i = 0; i < f->skip_lines; i++)
io_scan(&f->io, &smp, 1);
f->formatter->scan(f->stream_in, smp);
sample_free(smp);
@ -332,25 +332,20 @@ int file_start(struct vnode *n)
int file_stop(struct vnode *n)
{
int ret;
struct file *f = (struct file *) n->_vd;
f->task.stop();
ret = io_close(&f->io);
if (ret)
return ret;
ret = io_destroy(&f->io);
if (ret)
return ret;
fclose(f->stream_in);
fclose(f->stream_out);
delete f->formatter;
delete f->uri;
return 0;
}
int file_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int file_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct file *f = (struct file *) n->_vd;
int ret;
@ -358,15 +353,15 @@ int file_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *re
assert(cnt == 1);
retry: ret = io_scan(&f->io, smps, cnt);
retry: ret = f->formatter->scan(f->stream_in, smps, cnt);
if (ret <= 0) {
if (io_eof(&f->io)) {
if (feof(f->stream_in)) {
switch (f->eof_mode) {
case file::EOFBehaviour::REWIND:
n->logger->info("Rewind input file");
f->offset = file_calc_offset(&f->first, &f->epoch, f->epoch_mode);
io_rewind(&f->io);
rewind(f->stream_in);
goto retry;
case file::EOFBehaviour::SUSPEND:
@ -374,15 +369,7 @@ retry: ret = io_scan(&f->io, smps, cnt);
usleep(100000);
/* Try to download more data if this is a remote file. */
switch (f->io.mode) {
case IOMode::STDIO:
clearerr(f->io.in.stream);
break;
case IOMode::CUSTOM:
break;
}
clearerr(f->stream_in);
goto retry;
case file::EOFBehaviour::STOP:
@ -426,17 +413,20 @@ retry: ret = io_scan(&f->io, smps, cnt);
return cnt;
}
int file_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int file_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret;
struct file *f = (struct file *) n->_vd;
assert(cnt == 1);
ret = io_print(&f->io, smps, cnt);
ret = f->formatter->print(f->stream_out, smps, cnt);
if (ret < 0)
return ret;
if (f->flush)
fflush(f->stream_out);
return cnt;
}
@ -450,7 +440,7 @@ int file_poll_fds(struct vnode *n, int fds[])
return 1;
}
else if (f->epoch_mode == file::EpochMode::ORIGINAL) {
fds[0] = io_fd(&f->io);
fds[0] = fileno(f->stream_in);
return 1;
}

View file

@ -273,7 +273,7 @@ int fpga_stop(struct vnode *n)
return 0;
}
int fpga_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int fpga_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
unsigned read;
struct fpga *f = (struct fpga *) n->_vd;
@ -293,7 +293,7 @@ int fpga_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *re
return read;
}
int fpga_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int fpga_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int written;
struct fpga *f = (struct fpga *) n->_vd;

View file

@ -35,6 +35,7 @@
#define CONFIG_SV_DEFAULT_VLAN_ID 0
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
const struct iec61850_type_descriptor type_descriptors[] = {

View file

@ -34,7 +34,9 @@
#define CONFIG_SV_DEFAULT_PRIORITY 4
#define CONFIG_SV_DEFAULT_VLAN_ID 0
using namespace villas;
using namespace villas::utils;
using namespace villas::node;
static void iec61850_sv_listener(SVSubscriber subscriber, void *ctx, SVSubscriber_ASDU asdu)
{
@ -382,7 +384,7 @@ int iec61850_sv_destroy(struct vnode *n)
return 0;
}
int iec61850_sv_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int iec61850_sv_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int pulled;
struct iec61850_sv *i = (struct iec61850_sv *) n->_vd;
@ -399,7 +401,7 @@ int iec61850_sv_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsig
return pulled;
}
int iec61850_sv_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int iec61850_sv_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct iec61850_sv *i = (struct iec61850_sv *) n->_vd;

View file

@ -29,11 +29,12 @@
#include <villas/nodes/infiniband.hpp>
#include <villas/plugin.h>
#include <villas/utils.hpp>
#include <villas/format_type.h>
#include <villas/memory.h>
#include <villas/memory/ib.h>
#include <villas/timing.h>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
static int ib_disconnect(struct vnode *n)
@ -725,7 +726,7 @@ int ib_stop(struct vnode *n)
return 0;
}
int ib_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int ib_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct infiniband *ib = (struct infiniband *) n->_vd;
struct ibv_wc wc[cnt];
@ -865,7 +866,7 @@ int ib_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *rele
return read_values;
}
int ib_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int ib_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct infiniband *ib = (struct infiniband *) n->_vd;
struct ibv_send_wr wr[cnt], *bad_wr = nullptr;

View file

@ -35,6 +35,7 @@
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
int influxdb_parse(struct vnode *n, json_t *json)
@ -119,7 +120,7 @@ int influxdb_close(struct vnode *n)
return 0;
}
int influxdb_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int influxdb_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct influxdb *i = (struct influxdb *) n->_vd;
@ -127,7 +128,7 @@ int influxdb_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigne
ssize_t sentlen, buflen;
for (unsigned k = 0; k < cnt; k++) {
struct sample *smp = smps[k];
const struct sample *smp = smps[k];
/* Key */
strcatf(&buf, "%s", i->key);
@ -135,7 +136,7 @@ int influxdb_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigne
/* Fields */
for (unsigned j = 0; j < smp->length; j++) {
struct signal *sig = (struct signal *) vlist_at(smp->signals, j);
union signal_data *data = &smp->data[j];
const union signal_data *data = &smp->data[j];
if (
sig->type != SignalType::BOOLEAN &&

View file

@ -27,10 +27,10 @@
#include <villas/nodes/kafka.hpp>
#include <villas/plugin.h>
#include <villas/utils.hpp>
#include <villas/format_type.h>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
// Each process has a list of clients for which a thread invokes the kafka loop
@ -62,7 +62,6 @@ static void kafka_logger_cb(const rd_kafka_t *rk, int level, const char *fac, co
default:
logger->info("{}: {}", fac, buf);
break;
}
}
@ -81,7 +80,7 @@ static void kafka_message_cb(void *ctx, const rd_kafka_message_t *msg)
return;
}
ret = io_sscan(&k->io, (char *) msg->payload, msg->len, nullptr, smps, n->in.vectorize);
ret = k->formatter->sscan((char *) msg->payload, msg->len, nullptr, smps, n->in.vectorize);
if (ret < 0) {
n->logger->warn("Received an invalid message");
n->logger->warn(" Payload: {}", (char *) msg->payload);
@ -171,7 +170,6 @@ int kafka_parse(struct vnode *n, json_t *json)
struct kafka *k = (struct kafka *) n->_vd;
const char *server;
const char *format = "villas.binary";
const char *produce = nullptr;
const char *consume = nullptr;
const char *protocol;
@ -181,14 +179,15 @@ int kafka_parse(struct vnode *n, json_t *json)
json_error_t err;
json_t *json_ssl = nullptr;
json_t *json_sasl = nullptr;
json_t *json_format = nullptr;
ret = json_unpack_ex(json, &err, 0, "{ s?: { s?: s }, s?: { s?: s, s?: s }, s?: s, s: s, s?: F, s: s, s?: s, s?: o, s?: o }",
ret = json_unpack_ex(json, &err, 0, "{ s?: { s?: s }, s?: { s?: s, s?: s }, s?: o, s: s, s?: F, s: s, s?: s, s?: o, s?: o }",
"out",
"produce", &produce,
"in",
"consume", &consume,
"group_id", &group_id,
"format", &format,
"format", &json_format,
"server", &server,
"timeout", &k->timeout,
"protocol", &protocol,
@ -245,10 +244,12 @@ int kafka_parse(struct vnode *n, json_t *json)
k->sasl.password = strdup(password);
}
k->format = format_type_lookup(format);
if (!k->format)
throw ConfigError(json_ssl, "node-config-node-kafka-format", "Invalid format '{}' for node {}", format, node_name(n));
/* Format */
k->formatter = json_format
? FormatFactory::make(json_format)
: FormatFactory::make("villas.binary");
if (!k->formatter)
throw ConfigError(json_format, "node-config-node-kafka-format", "Invalid format configuration");
return 0;
}
@ -257,9 +258,7 @@ int kafka_prepare(struct vnode *n)
int ret;
struct kafka *k = (struct kafka *) n->_vd;
ret = io_init(&k->io, k->format, &n->in.signals, (int) SampleFlags::HAS_ALL & ~(int) SampleFlags::HAS_OFFSET);
if (ret)
return ret;
k->formatter->start(&n->in.signals, ~(int) SampleFlags::HAS_OFFSET);
ret = pool_init(&k->pool, 1024, SAMPLE_LENGTH(vlist_length(&n->in.signals)));
if (ret)
@ -278,7 +277,7 @@ char * kafka_print(struct vnode *n)
char *buf = nullptr;
strcatf(&buf, "format=%s, bootstrap.server=%s, client.id=%s, security.protocol=%s", format_type_name(k->format),
strcatf(&buf, "bootstrap.server=%s, client.id=%s, security.protocol=%s",
k->server,
k->client_id,
k->protocol
@ -305,9 +304,7 @@ int kafka_destroy(struct vnode *n)
if (k->consumer.client)
rd_kafka_destroy(k->consumer.client);
ret = io_destroy(&k->io);
if (ret)
return ret;
delete k->formatter;
ret = pool_destroy(&k->pool);
if (ret)
@ -528,7 +525,7 @@ kafka_error:
return ret;
}
int kafka_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int kafka_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int pulled;
struct kafka *k = (struct kafka *) n->_vd;
@ -542,7 +539,7 @@ int kafka_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *r
return pulled;
}
int kafka_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int kafka_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret;
struct kafka *k = (struct kafka *) n->_vd;
@ -551,7 +548,7 @@ int kafka_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *
char data[4096];
ret = io_sprint(&k->io, data, sizeof(data), &wbytes, smps, cnt);
ret = k->formatter->sprint(data, sizeof(data), &wbytes, smps, cnt);
if (ret < 0)
return ret;

View file

@ -30,6 +30,7 @@
#include <villas/memory.h>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
static struct plugin p;
@ -95,7 +96,7 @@ int loopback_destroy(struct vnode *n)
return queue_signalled_destroy(&l->queue);
}
int loopback_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int loopback_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int avail;
@ -112,7 +113,7 @@ int loopback_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned
return avail;
}
int loopback_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int loopback_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct loopback *l = (struct loopback *) n->_vd;

View file

@ -30,6 +30,7 @@
#include <villas/memory.h>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
static struct plugin p;
@ -62,7 +63,7 @@ int loopback_internal_destroy(struct vnode *n)
return queue_signalled_destroy(&l->queue);
}
int loopback_internal_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int loopback_internal_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int avail;
@ -79,7 +80,7 @@ int loopback_internal_read(struct vnode *n, struct sample *smps[], unsigned cnt,
return avail;
}
int loopback_internal_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int loopback_internal_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct loopback_internal *l = (struct loopback_internal *) n->_vd;

View file

@ -26,10 +26,10 @@
#include <villas/nodes/mqtt.hpp>
#include <villas/plugin.h>
#include <villas/utils.hpp>
#include <villas/format_type.h>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
// Each process has a list of clients for which a thread invokes the mosquitto loop
@ -138,7 +138,7 @@ static void mqtt_message_cb(struct mosquitto *mosq, void *ctx, const struct mosq
return;
}
ret = io_sscan(&m->io, (char *) msg->payload, msg->payloadlen, nullptr, smps, n->in.vectorize);
ret = m->formatter->sscan((char *) msg->payload, msg->payloadlen, nullptr, smps, n->in.vectorize);
if (ret < 0) {
n->logger->warn("Received an invalid message");
n->logger->warn(" Payload: {}", (char *) msg->payload);
@ -225,7 +225,6 @@ int mqtt_parse(struct vnode *n, json_t *json)
struct mqtt *m = (struct mqtt *) n->_vd;
const char *host;
const char *format = "villas.binary";
const char *publish = nullptr;
const char *subscribe = nullptr;
const char *username = nullptr;
@ -233,13 +232,14 @@ int mqtt_parse(struct vnode *n, json_t *json)
json_error_t err;
json_t *json_ssl = nullptr;
json_t *json_format = nullptr;
ret = json_unpack_ex(json, &err, 0, "{ s?: { s?: s }, s?: { s?: s }, s?: s, s: s, s?: i, s?: i, s?: i, s?: b, s?: s, s?: s, s?: o }",
ret = json_unpack_ex(json, &err, 0, "{ s?: { s?: s }, s?: { s?: s }, s?: o, s: s, s?: i, s?: i, s?: i, s?: b, s?: s, s?: s, s?: o }",
"out",
"publish", &publish,
"in",
"subscribe", &subscribe,
"format", &format,
"format", &json_format,
"host", &host,
"port", &m->port,
"qos", &m->qos,
@ -289,10 +289,12 @@ int mqtt_parse(struct vnode *n, json_t *json)
m->ssl.keyfile = keyfile ? strdup(keyfile) : nullptr;
}
m->format = format_type_lookup(format);
if (!m->format)
throw ConfigError(json_ssl, "node-config-node-mqtt-format", "Invalid format '{}' for node {}", format, node_name(n));
/* Format */
m->formatter = json_format
? FormatFactory::make(json_format)
: FormatFactory::make("json");
if (!m->formatter)
throw ConfigError(json_format, "node-config-node-mqtt-format", "Invalid format configuration");
return 0;
}
@ -317,9 +319,7 @@ int mqtt_prepare(struct vnode *n)
int ret;
struct mqtt *m = (struct mqtt *) n->_vd;
ret = io_init(&m->io, m->format, &n->in.signals, (int) SampleFlags::HAS_ALL & ~(int) SampleFlags::HAS_OFFSET);
if (ret)
return ret;
m->formatter->start(&n->in.signals, ~(int) SampleFlags::HAS_OFFSET);
ret = pool_init(&m->pool, 1024, SAMPLE_LENGTH(vlist_length(&n->in.signals)));
if (ret)
@ -338,7 +338,7 @@ char * mqtt_print(struct vnode *n)
char *buf = nullptr;
strcatf(&buf, "format=%s, host=%s, port=%d, keepalive=%d, ssl=%s", format_type_name(m->format),
strcatf(&buf, "host=%s, port=%d, keepalive=%d, ssl=%s",
m->host,
m->port,
m->keepalive,
@ -365,9 +365,7 @@ int mqtt_destroy(struct vnode *n)
mosquitto_destroy(m->client);
ret = io_destroy(&m->io);
if (ret)
return ret;
delete m->formatter;
ret = pool_destroy(&m->pool);
if (ret)
@ -512,7 +510,7 @@ mosquitto_error:
return ret;
}
int mqtt_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int mqtt_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int pulled;
struct mqtt *m = (struct mqtt *) n->_vd;
@ -526,7 +524,7 @@ int mqtt_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *re
return pulled;
}
int mqtt_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int mqtt_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret;
struct mqtt *m = (struct mqtt *) n->_vd;
@ -535,7 +533,7 @@ int mqtt_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *r
char data[1500];
ret = io_sprint(&m->io, data, sizeof(data), &wbytes, smps, cnt);
ret = m->formatter->sprint(data, sizeof(data), &wbytes, smps, cnt);
if (ret < 0)
return ret;

View file

@ -27,10 +27,10 @@
#include <villas/plugin.h>
#include <villas/nodes/nanomsg.hpp>
#include <villas/utils.hpp>
#include <villas/format_type.h>
#include <villas/exceptions.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::utils;
int nanomsg_reverse(struct vnode *n)
@ -86,10 +86,8 @@ int nanomsg_parse(struct vnode *n, json_t *json)
int ret;
struct nanomsg *m = (struct nanomsg *) n->_vd;
const char *format = "villas.binary";
json_error_t err;
json_t *json_format = nullptr;
json_t *json_out_endpoints = nullptr;
json_t *json_in_endpoints = nullptr;
@ -101,8 +99,8 @@ int nanomsg_parse(struct vnode *n, json_t *json)
if (ret)
return ret;
ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: { s?: o }, s?: { s?: o } }",
"format", &format,
ret = json_unpack_ex(json, &err, 0, "{ s?: o, s?: { s?: o }, s?: { s?: o } }",
"format", &json_format,
"out",
"endpoints", &json_out_endpoints,
"in",
@ -123,9 +121,12 @@ int nanomsg_parse(struct vnode *n, json_t *json)
throw RuntimeError("Invalid type for 'subscribe' setting");
}
m->format = format_type_lookup(format);
if (!m->format)
throw RuntimeError("Invalid format '{}'", format);
/* Format */
m->formatter = json_format
? FormatFactory::make(json_format)
: FormatFactory::make("json");
if (!m->formatter)
throw ConfigError(json_format, "node-config-node-nanomsg-format", "Invalid format configuration");
return 0;
}
@ -136,7 +137,7 @@ char * nanomsg_print(struct vnode *n)
char *buf = nullptr;
strcatf(&buf, "format=%s, in.endpoints=[ ", format_type_name(m->format));
strcatf(&buf, "in.endpoints=[ ");
for (size_t i = 0; i < vlist_length(&m->in.endpoints); i++) {
char *ep = (char *) vlist_at(&m->in.endpoints, i);
@ -162,9 +163,7 @@ int nanomsg_start(struct vnode *n)
int ret;
struct nanomsg *m = (struct nanomsg *) n->_vd;
ret = io_init(&m->io, m->format, &n->in.signals, (int) SampleFlags::HAS_ALL & ~(int) SampleFlags::HAS_OFFSET);
if (ret)
return ret;
m->formatter->start(&n->in.signals, ~(int) SampleFlags::HAS_OFFSET);
ret = m->in.socket = nn_socket(AF_SP, NN_SUB);
if (ret < 0)
@ -213,9 +212,7 @@ int nanomsg_stop(struct vnode *n)
if (ret < 0)
return ret;
ret = io_destroy(&m->io);
if (ret)
return ret;
delete m->formatter;
return 0;
}
@ -227,7 +224,7 @@ int nanomsg_type_stop()
return 0;
}
int nanomsg_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int nanomsg_read(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
struct nanomsg *m = (struct nanomsg *) n->_vd;
int bytes;
@ -238,10 +235,10 @@ int nanomsg_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned
if (bytes < 0)
return -1;
return io_sscan(&m->io, data, bytes, nullptr, smps, cnt);
return m->formatter->sscan(data, bytes, nullptr, smps, cnt);
}
int nanomsg_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release)
int nanomsg_write(struct vnode *n, struct sample * const smps[], unsigned cnt)
{
int ret;
struct nanomsg *m = (struct nanomsg *) n->_vd;
@ -250,7 +247,7 @@ int nanomsg_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned
char data[NANOMSG_MAX_PACKET_LEN];
ret = io_sprint(&m->io, data, sizeof(data), &wbytes, smps, cnt);
ret = m->formatter->sprint(data, sizeof(data), &wbytes, smps, cnt);
if (ret <= 0)
return -1;

Some files were not shown because too many files have changed in this diff Show more