2021-05-10 00:12:30 +02:00
|
|
|
/* Reading and writing simulation samples in various formats.
|
|
|
|
*
|
2022-03-15 09:18:01 -04:00
|
|
|
* Author: Steffen Vogel <post@steffenvogel.de>
|
2022-03-15 09:28:57 -04:00
|
|
|
* SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
2022-07-04 18:20:03 +02:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2021-05-10 00:12:30 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <cstdio>
|
2023-09-07 11:46:39 +02:00
|
|
|
#include <cstdlib>
|
2021-05-10 00:12:30 +02:00
|
|
|
#include <cstring>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
#include <villas/exceptions.hpp>
|
2021-05-10 00:12:30 +02:00
|
|
|
#include <villas/format.hpp>
|
2023-09-07 11:46:39 +02:00
|
|
|
#include <villas/node/config.hpp>
|
2021-08-10 10:12:48 -04:00
|
|
|
#include <villas/sample.hpp>
|
2023-09-07 11:46:39 +02:00
|
|
|
#include <villas/utils.hpp>
|
2021-05-10 00:12:30 +02:00
|
|
|
|
|
|
|
using namespace villas;
|
|
|
|
using namespace villas::node;
|
|
|
|
using namespace villas::utils;
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
Format *FormatFactory::make(json_t *json) {
|
|
|
|
std::string type;
|
|
|
|
Format *f;
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
if (json_is_string(json)) {
|
|
|
|
type = json_string_value(json);
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
return FormatFactory::make(type);
|
|
|
|
} else if (json_is_object(json)) {
|
|
|
|
json_t *json_type = json_object_get(json, "type");
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
type = json_string_value(json_type);
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
f = FormatFactory::make(type);
|
|
|
|
if (!f)
|
|
|
|
return nullptr;
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
f->parse(json);
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
return f;
|
|
|
|
} else
|
|
|
|
throw ConfigError(json, "node-config-format", "Invalid format config");
|
2021-05-10 00:12:30 +02:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
Format *FormatFactory::make(const std::string &format) {
|
|
|
|
FormatFactory *ff = plugin::registry->lookup<FormatFactory>(format);
|
|
|
|
if (!ff)
|
|
|
|
throw RuntimeError("Unknown format: {}", format);
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
return ff->make();
|
2021-05-10 00:12:30 +02:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
Format::Format(int fl) : flags(fl), real_precision(17), signals(nullptr) {
|
|
|
|
in.buflen = out.buflen = DEFAULT_FORMAT_BUFFER_LENGTH;
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
in.buffer = new char[in.buflen];
|
|
|
|
out.buffer = new char[out.buflen];
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
if (!in.buffer || !out.buffer)
|
|
|
|
throw MemoryAllocationError();
|
2021-05-10 00:12:30 +02:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
Format::~Format() {
|
|
|
|
int ret __attribute__((unused));
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
delete[] in.buffer;
|
|
|
|
delete[] out.buffer;
|
2021-05-10 00:12:30 +02:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
void Format::start(SignalList::Ptr sigs, int fl) {
|
|
|
|
flags &= fl;
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
signals = sigs;
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
start();
|
2021-05-10 00:12:30 +02:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
void Format::start(const std::string &dtypes, int fl) {
|
2024-04-09 23:39:34 +02:00
|
|
|
flags &= fl;
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
signals = std::make_shared<SignalList>(dtypes.c_str());
|
|
|
|
if (!signals)
|
|
|
|
throw MemoryAllocationError();
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
start();
|
2021-05-10 00:12:30 +02:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
int Format::print(FILE *f, const struct Sample *const smps[], unsigned cnt) {
|
|
|
|
int ret;
|
|
|
|
size_t wbytes;
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
ret = sprint(out.buffer, out.buflen, &wbytes, smps, cnt);
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
fwrite(out.buffer, wbytes, 1, f);
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
return ret;
|
2021-05-10 00:12:30 +02:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
int Format::scan(FILE *f, struct Sample *const smps[], unsigned cnt) {
|
|
|
|
size_t bytes, rbytes;
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
bytes = fread(in.buffer, 1, in.buflen, f);
|
2021-05-10 00:12:30 +02:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
return sscan(in.buffer, bytes, &rbytes, smps, cnt);
|
2021-05-10 00:12:30 +02:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
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;
|
2021-05-10 00:12:30 +02:00
|
|
|
}
|