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

add new format-type for OPAL-RT's AsyncIP example

This commit is contained in:
Steffen Vogel 2022-02-24 04:33:44 -05:00
parent ca533ac8e0
commit d4f74a5a51
8 changed files with 256 additions and 33 deletions

View file

@ -0,0 +1,93 @@
/** A custom format for OPAL-RTs AsyncIP example
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2021, 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>
namespace villas {
namespace node {
/* Forward declarations. */
struct Sample;
class OpalAsyncIPFormat : public BinaryFormat {
protected:
const int MAXSIZE = 64;
struct Payload {
int16_t dev_id; // (2 bytes) Sender device ID
int32_t msg_id; // (4 bytes) Message ID
int16_t msg_len; // (2 bytes) Message length (data only)
double data[]; // Up to MAXSIZE doubles (8 bytes each)
} __attribute__((packed));
int16_t dev_id;
public:
OpalAsyncIPFormat(int fl, uint8_t did = 0) :
BinaryFormat(fl),
dev_id(did)
{ }
virtual
int sscan(const char *buf, size_t len, size_t *rbytes, struct Sample * const smps[], unsigned cnt);
virtual
int sprint(char *buf, size_t len, size_t *wbytes, const struct Sample * const smps[], unsigned cnt);
virtual
void parse(json_t *json);
};
class OpalAsyncIPFormatPlugin : public FormatFactory {
public:
using FormatFactory::FormatFactory;
virtual
Format * make()
{
return new OpalAsyncIPFormat((int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA);
}
/// Get plugin name
virtual
std::string getName() const
{
return "opal.asyncip";
}
/// Get plugin description
virtual
std::string getDescription() const
{
return "OPAL-RTs AsyncIP example format";
}
};
} /* namespace node */
} /* namespace villas */

View file

@ -63,7 +63,7 @@ union SignalData {
}
/** Convert signal data from one description/format to another. */
void cast(enum SignalType type, enum SignalType to);
SignalData cast(enum SignalType type, enum SignalType to) const;
/** Set data from double */
void set(enum SignalType type, double val);

View file

@ -68,6 +68,7 @@ list(APPEND FORMAT_SRC
json.cpp
line.cpp
msg.cpp
opal_asyncip.cpp
raw.cpp
value.cpp
villas_binary.cpp

View file

@ -0,0 +1,132 @@
/** A custom format for OPAL-RTs AsyncIP example
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2021, 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 <endian.h>
#include <villas/formats/opal_asyncip.hpp>
#include <villas/exceptions.hpp>
#include <villas/sample.hpp>
#include <villas/utils.hpp>
using namespace villas;
using namespace villas::node;
int OpalAsyncIPFormat::sprint(char *buf, size_t len, size_t *wbytes, const struct Sample * const smps[], unsigned cnt)
{
unsigned i;
auto *ptr = buf;
ssize_t slen = len;
for (i = 0; i < cnt && ptr - buf < slen; i++) {
auto *pl = (struct Payload *) ptr;
auto *smp = smps[i];
auto wlen = smp->length * sizeof(double) + sizeof(struct Payload);
if (wlen > len)
return -1;
pl->dev_id = htole16(dev_id);
pl->msg_id = htole32(smp->sequence);
pl->msg_len = htole16(smp->length * sizeof(double));
for (unsigned j = 0; j < smp->length; j++) {
auto sig = smp->signals->getByIndex(j);
auto d = smp->data[j];
d = d.cast(sig->type, SignalType::FLOAT);
d.i = htole64(d.i);
pl->data[j] = d.f;
}
ptr += wlen;
}
if (wbytes)
*wbytes = ptr - buf;
return i;
}
int OpalAsyncIPFormat::sscan(const char *buf, size_t len, size_t *rbytes, struct Sample * const smps[], unsigned cnt)
{
unsigned i;
auto *ptr = buf;
ssize_t slen = len;
if (len % 8 != 0)
return -1; /* Packet size is invalid: Must be multiple of 4 bytes */
for (i = 0; i < cnt && ptr - buf + sizeof(struct Payload) < slen; i++) {
if (len < 8)
return -1; /* Packet size is invalid: Must be multiple of 4 bytes */
auto *pl = (struct Payload *) ptr;
auto *smp = smps[i];
auto rlen = le16toh(pl->msg_len);
if (len < ptr - buf + rlen + sizeof(struct Payload))
return -2;
smp->sequence = le32toh(pl->msg_id);
smp->length = rlen / sizeof(double);
smp->flags = (int) SampleFlags::HAS_SEQUENCE;
smp->signals = signals;
for (unsigned j = 0; j < MIN(smp->length, smp->capacity); j++) {
auto sig = signals->getByIndex(j);
SignalData d;
d.f = pl->data[j];
d.i = le64toh(d.i);
smp->data[j] = d.cast(SignalType::FLOAT, sig->type);
}
ptr += rlen + sizeof(struct Payload);
}
if (rbytes)
*rbytes = ptr - buf;
return i;
}
void OpalAsyncIPFormat::parse(json_t *json)
{
int ret;
json_error_t err;
int did = -1;
ret = json_unpack_ex(json, &err, 0, "{ s?: i }",
"dev_id", &did
);
if (ret)
throw ConfigError(json, err, "node-config-format-opal-asyncip", "Failed to parse format configuration");
if (did >= 0)
dev_id = did;
Format::parse(json);
}
static OpalAsyncIPFormatPlugin p;

View file

@ -109,7 +109,7 @@ public:
auto orig_sig = smp->signals->getByIndex(index);
auto new_sig = signals->getByIndex(index);
smp->data[index].cast(orig_sig->type, new_sig->type);
smp->data[index] = smp->data[index].cast(orig_sig->type, new_sig->type);
}
return Reason::OK;

View file

@ -164,7 +164,7 @@ void lua_tosignaldata(lua_State *L, union SignalData *data, enum SignalType targ
return;
}
data->cast(type, targetType);
*data = data->cast(type, targetType);
}
static

View file

@ -53,98 +53,95 @@ void SignalData::set(enum SignalType type, double val)
}
}
void SignalData::cast(enum SignalType from, enum SignalType to)
SignalData SignalData::cast(enum SignalType from, enum SignalType to) const
{
if (from == to) /* Nothing to do */
return;
SignalData n = *this;
switch (to) {
case SignalType::BOOLEAN:
switch(from) {
case SignalType::BOOLEAN:
break;
case SignalType::INTEGER:
this->b = this->i;
n.b = this->i;
break;
case SignalType::FLOAT:
this->b = this->f;
n.b = this->f;
break;
case SignalType::COMPLEX:
this->b = std::real(this->z);
n.b = std::real(this->z);
break;
default: { }
case SignalType::INVALID:
case SignalType::BOOLEAN:
break;
}
break;
case SignalType::INTEGER:
switch(from) {
case SignalType::BOOLEAN:
this->i = this->b;
break;
case SignalType::INTEGER:
n.i = this->b;
break;
case SignalType::FLOAT:
this->i = this->f;
n.i = this->f;
break;
case SignalType::COMPLEX:
this->i = std::real(this->z);
n.i = std::real(this->z);
break;
default: { }
case SignalType::INVALID:
case SignalType::INTEGER:
break;
}
break;
case SignalType::FLOAT:
switch(from) {
case SignalType::BOOLEAN:
this->f = this->b;
n.f = this->b;
break;
case SignalType::INTEGER:
this->f = this->i;
break;
case SignalType::FLOAT:
n.f = this->i;
break;
case SignalType::COMPLEX:
this->f = std::real(this->z);
n.f = std::real(this->z);
break;
default: { }
case SignalType::INVALID:
case SignalType::FLOAT:
break;
}
break;
case SignalType::COMPLEX:
switch(from) {
case SignalType::BOOLEAN:
this->z = this->b;
n.z = this->b;
break;
case SignalType::INTEGER:
this->z = this->i;
n.z = this->i;
break;
case SignalType::FLOAT:
this->z = this->f;
n.z = this->f;
break;
case SignalType::INVALID:
case SignalType::COMPLEX:
break;
default: { }
}
break;
default: { }
}
return n;
}
int SignalData::parseString(enum SignalType type, const char *ptr, char **end)

View file

@ -33,7 +33,7 @@ function finish {
}
trap finish EXIT
FORMATS="villas.human csv tsv json"
FORMATS="villas.human csv tsv json opal.asyncip"
villas signal -v5 -n -l20 mixed > input.dat