2023-09-04 12:21:37 +02:00
|
|
|
/* A custom format for OPAL-RTs AsyncIP example.
|
2022-02-24 04:33:44 -05:00
|
|
|
*
|
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
|
2022-02-24 04:33:44 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <endian.h>
|
|
|
|
|
|
|
|
#include <villas/exceptions.hpp>
|
2023-09-07 11:46:39 +02:00
|
|
|
#include <villas/formats/opal_asyncip.hpp>
|
2022-02-24 04:33:44 -05:00
|
|
|
#include <villas/sample.hpp>
|
|
|
|
#include <villas/utils.hpp>
|
|
|
|
|
|
|
|
using namespace villas;
|
|
|
|
using namespace villas::node;
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
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;
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
for (i = 0; i < cnt && ptr - buf < slen; i++) {
|
|
|
|
auto *pl = (struct Payload *)ptr;
|
|
|
|
auto *smp = smps[i];
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
auto wlen = smp->length * sizeof(double) + sizeof(struct Payload);
|
|
|
|
if (wlen > len)
|
|
|
|
return -1;
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
pl->dev_id = htole16(dev_id);
|
|
|
|
pl->msg_id = htole32(smp->sequence);
|
|
|
|
pl->msg_len = htole16(smp->length * sizeof(double));
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
if (smp->length > MAXSIZE)
|
|
|
|
logger->warn("Can not sent more then {} signals via opal.asyncip format. "
|
|
|
|
"We only send the first {}..",
|
|
|
|
MAXSIZE, MAXSIZE);
|
2022-02-24 07:31:00 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
for (unsigned j = 0; j < MIN(MAXSIZE, smp->length); j++) {
|
|
|
|
auto sig = smp->signals->getByIndex(j);
|
|
|
|
auto d = smp->data[j];
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
d = d.cast(sig->type, SignalType::FLOAT);
|
|
|
|
d.i = htole64(d.i);
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
pl->data[j] = d.f;
|
|
|
|
}
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
ptr += wlen;
|
|
|
|
}
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
if (wbytes)
|
|
|
|
*wbytes = ptr - buf;
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
return i;
|
2022-02-24 04:33:44 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
int OpalAsyncIPFormat::sscan(const char *buf, size_t len, size_t *rbytes,
|
|
|
|
struct Sample *const smps[], unsigned cnt) {
|
|
|
|
unsigned i;
|
|
|
|
auto *ptr = buf;
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
if (len % 8 != 0)
|
|
|
|
return -1; // Packet size is invalid: Must be multiple of 8 bytes
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
for (i = 0; i < cnt && ptr - buf + sizeof(struct Payload) < len; i++) {
|
|
|
|
auto *pl = (struct Payload *)ptr;
|
|
|
|
auto *smp = smps[i];
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
auto rlen = le16toh(pl->msg_len);
|
|
|
|
if (len < ptr - buf + rlen + sizeof(struct Payload))
|
|
|
|
return -2;
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
smp->sequence = le32toh(pl->msg_id);
|
|
|
|
smp->length = rlen / sizeof(double);
|
|
|
|
smp->flags = (int)SampleFlags::HAS_SEQUENCE | (int)SampleFlags::HAS_DATA;
|
|
|
|
smp->signals = signals;
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
for (unsigned j = 0; j < MIN(smp->length, smp->capacity); j++) {
|
|
|
|
auto sig = signals->getByIndex(j);
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
SignalData d;
|
|
|
|
d.f = pl->data[j];
|
|
|
|
d.i = le64toh(d.i);
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
smp->data[j] = d.cast(SignalType::FLOAT, sig->type);
|
|
|
|
}
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
ptr += rlen + sizeof(struct Payload);
|
|
|
|
}
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
if (rbytes)
|
|
|
|
*rbytes = ptr - buf;
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
return i;
|
2022-02-24 04:33:44 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
void OpalAsyncIPFormat::parse(json_t *json) {
|
|
|
|
int ret;
|
|
|
|
json_error_t err;
|
|
|
|
int did = -1;
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
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");
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
if (did >= 0)
|
|
|
|
dev_id = did;
|
2022-02-24 04:33:44 -05:00
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
Format::parse(json);
|
2022-02-24 04:33:44 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 11:46:39 +02:00
|
|
|
static OpalAsyncIPFormatPlugin p;
|