mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
Apply clang-format changes
Signed-off-by: Steffen Vogel <steffen.vogel@opal-rt.com>
This commit is contained in:
parent
c7c0514826
commit
aa16979fdd
300 changed files with 30949 additions and 33000 deletions
|
@ -8,18 +8,18 @@
|
|||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#define PROGNAME "VILLASnode-OPAL-UDP"
|
||||
#define VERSION "0.7"
|
||||
#define PROGNAME "VILLASnode-OPAL-UDP"
|
||||
#define VERSION "0.7"
|
||||
|
||||
#define MAX_VALUES 64
|
||||
#define MAX_VALUES 64
|
||||
|
||||
// List of protocols
|
||||
#define VILLAS 1
|
||||
#define GTNET_SKT 2
|
||||
#define VILLAS 1
|
||||
#define GTNET_SKT 2
|
||||
|
||||
// Default protocol
|
||||
#ifndef PROTOCOL
|
||||
#define PROTOCOL VILLAS
|
||||
#define PROTOCOL VILLAS
|
||||
#endif // PROTOCOL
|
||||
|
||||
#endif // _CONFIG_H_
|
||||
|
|
|
@ -10,65 +10,63 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// The current version number for the message format
|
||||
#define MSG_VERSION 2
|
||||
#define MSG_VERSION 2
|
||||
|
||||
// TODO: Implement more message types
|
||||
#define MSG_TYPE_DATA 0 // Message contains float values
|
||||
#define MSG_TYPE_START 1 // Message marks the beginning of a new simulation case
|
||||
#define MSG_TYPE_STOP 2 // Message marks the end of a simulation case
|
||||
#define MSG_TYPE_DATA 0 // Message contains float values
|
||||
#define MSG_TYPE_START 1 // Message marks the beginning of a new simulation case
|
||||
#define MSG_TYPE_STOP 2 // Message marks the end of a simulation case
|
||||
|
||||
// The total size in bytes of a message
|
||||
#define MSG_LEN(values) (sizeof(struct msg) + MSG_DATA_LEN(values))
|
||||
#define MSG_LEN(values) (sizeof(struct msg) + MSG_DATA_LEN(values))
|
||||
|
||||
// The length of \p values values in bytes
|
||||
#define MSG_DATA_LEN(values) (sizeof(float) * (values))
|
||||
#define MSG_DATA_LEN(values) (sizeof(float) * (values))
|
||||
|
||||
// The offset to the first data value in a message
|
||||
#define MSG_DATA_OFFSET(msg) ((char *) (msg) + offsetof(struct msg, data))
|
||||
#define MSG_DATA_OFFSET(msg) ((char *)(msg) + offsetof(struct msg, data))
|
||||
|
||||
// Initialize a message with default values
|
||||
#define MSG_INIT(len, seq) (struct msg) {\
|
||||
.version = MSG_VERSION, \
|
||||
.type = MSG_TYPE_DATA, \
|
||||
.length = len, \
|
||||
.sequence = seq, \
|
||||
.id = 0 \
|
||||
}
|
||||
#define MSG_INIT(len, seq) \
|
||||
(struct msg) { \
|
||||
.version = MSG_VERSION, .type = MSG_TYPE_DATA, .length = len, \
|
||||
.sequence = seq, .id = 0 \
|
||||
}
|
||||
|
||||
// The timestamp of a message in struct timespec format
|
||||
#define MSG_TS(msg) (struct timespec) { \
|
||||
.tv_sec = (msg)->ts.sec, \
|
||||
.tv_nsec = (msg)->ts.nsec \
|
||||
}
|
||||
#define MSG_TS(msg) \
|
||||
(struct timespec) { .tv_sec = (msg)->ts.sec, .tv_nsec = (msg)->ts.nsec }
|
||||
|
||||
// This message format is used by all clients
|
||||
struct msg
|
||||
{
|
||||
struct msg {
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
unsigned version: 4; // Specifies the format of the remaining message (see MGS_VERSION)
|
||||
unsigned type : 2; // Data or control message (see MSG_TYPE_*)
|
||||
unsigned reserved1 : 2; // Reserved bits
|
||||
unsigned
|
||||
version : 4; // Specifies the format of the remaining message (see MGS_VERSION)
|
||||
unsigned type : 2; // Data or control message (see MSG_TYPE_*)
|
||||
unsigned reserved1 : 2; // Reserved bits
|
||||
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||
unsigned reserved1 : 2; // Reserved bits
|
||||
unsigned type : 2; // Data or control message (see MSG_TYPE_*)
|
||||
unsigned version: 4; // Specifies the format of the remaining message (see MGS_VERSION)
|
||||
unsigned reserved1 : 2; // Reserved bits
|
||||
unsigned type : 2; // Data or control message (see MSG_TYPE_*)
|
||||
unsigned
|
||||
version : 4; // Specifies the format of the remaining message (see MGS_VERSION)
|
||||
#else
|
||||
#error Invalid byte-order
|
||||
#error Invalid byte-order
|
||||
#endif // BYTEORDER
|
||||
|
||||
uint8_t id; // An id which identifies the source of this sample
|
||||
uint16_t length; // The number of values in msg::data[]
|
||||
uint32_t sequence; // The sequence number is incremented by one for consecutive messages
|
||||
uint8_t id; // An id which identifies the source of this sample
|
||||
uint16_t length; // The number of values in msg::data[]
|
||||
uint32_t
|
||||
sequence; // The sequence number is incremented by one for consecutive messages
|
||||
|
||||
// A timestamp per message
|
||||
struct {
|
||||
uint32_t sec; // Seconds since 1970-01-01 00:00:00
|
||||
uint32_t nsec; // Nanoseconds of the current second
|
||||
} ts;
|
||||
// A timestamp per message
|
||||
struct {
|
||||
uint32_t sec; // Seconds since 1970-01-01 00:00:00
|
||||
uint32_t nsec; // Nanoseconds of the current second
|
||||
} ts;
|
||||
|
||||
// The message payload
|
||||
union {
|
||||
float f; // Floating point values
|
||||
uint32_t i; // Integer values
|
||||
} data[];
|
||||
// The message payload
|
||||
union {
|
||||
float f; // Floating point values
|
||||
uint32_t i; // Integer values
|
||||
} data[];
|
||||
} __attribute__((packed));
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
#define RT
|
||||
#include "OpalGenAsyncParamCtrl.h"
|
||||
|
||||
#define UDP_PROTOCOL 1
|
||||
#define TCP_PROTOCOL 2
|
||||
#define UDP_PROTOCOL 1
|
||||
#define TCP_PROTOCOL 2
|
||||
|
||||
struct socket {
|
||||
struct sockaddr_in send_ad; // Send address
|
||||
struct sockaddr_in recv_ad; // Receive address
|
||||
int sd; // socket descriptor
|
||||
struct sockaddr_in send_ad; // Send address
|
||||
struct sockaddr_in recv_ad; // Receive address
|
||||
int sd; // socket descriptor
|
||||
};
|
||||
|
||||
int socket_init(struct socket *s, Opal_GenAsyncParam_Ctrl IconCtrlStruct);
|
||||
|
|
|
@ -9,27 +9,21 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
size_t __intel_sse2_strlen(const char *s)
|
||||
{
|
||||
return strlen(s);
|
||||
size_t __intel_sse2_strlen(const char *s) { return strlen(s); }
|
||||
|
||||
void *_intel_fast_memset(void *b, int c, size_t len) {
|
||||
return memset(b, c, len);
|
||||
}
|
||||
|
||||
void * _intel_fast_memset(void *b, int c, size_t len)
|
||||
{
|
||||
return memset(b, c, len);
|
||||
void *_intel_fast_memcpy(void *restrict dst, const void *restrict src,
|
||||
size_t n) {
|
||||
return memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
void * _intel_fast_memcpy(void *restrict dst, const void *restrict src, size_t n)
|
||||
{
|
||||
return memcpy(dst, src, n);
|
||||
int _intel_fast_memcmp(const void *s1, const void *s2, size_t n) {
|
||||
return memcmp(s1, s2, n);
|
||||
}
|
||||
|
||||
int _intel_fast_memcmp(const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
return memcmp(s1, s2, n);
|
||||
}
|
||||
|
||||
void * _intel_fast_memmove(void *dest, const void *src, size_t num)
|
||||
{
|
||||
return memmove(dest, src, num);
|
||||
void *_intel_fast_memmove(void *dest, const void *src, size_t num) {
|
||||
return memmove(dest, src, num);
|
||||
}
|
||||
|
|
|
@ -6,22 +6,22 @@
|
|||
*/
|
||||
|
||||
// Standard ANSI C headers needed for this program
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Define RTLAB before including OpalPrint.h for messages to be sent
|
||||
* to the OpalDisplay. Otherwise stdout will be used. */
|
||||
#define RTLAB
|
||||
#include "OpalPrint.h"
|
||||
#include "AsyncApi.h"
|
||||
#include "OpalPrint.h"
|
||||
|
||||
// This is the message format
|
||||
#include "config.h"
|
||||
|
@ -29,322 +29,334 @@
|
|||
#include "utils.h"
|
||||
|
||||
#if PROTOCOL == VILLAS
|
||||
#include "msg.h"
|
||||
#include "msg_format.h"
|
||||
#include "msg.h"
|
||||
#include "msg_format.h"
|
||||
#endif
|
||||
|
||||
/* This is just for initializing the shared memory access to communicate
|
||||
* with the RT-LAB model. It's easier to remember the arguments like this */
|
||||
#define ASYNC_SHMEM_NAME argv[1]
|
||||
#define ASYNC_SHMEM_SIZE atoi(argv[2])
|
||||
#define PRINT_SHMEM_NAME argv[3]
|
||||
#define ASYNC_SHMEM_NAME argv[1]
|
||||
#define ASYNC_SHMEM_SIZE atoi(argv[2])
|
||||
#define PRINT_SHMEM_NAME argv[3]
|
||||
|
||||
// Global Variables
|
||||
struct socket skt;
|
||||
|
||||
static
|
||||
void * SendToIPPort(void *arg)
|
||||
{
|
||||
unsigned int ModelState, SendID, Sequence = 0;
|
||||
int nbSend = 0, ret, cnt, len;
|
||||
static void *SendToIPPort(void *arg) {
|
||||
unsigned int ModelState, SendID, Sequence = 0;
|
||||
int nbSend = 0, ret, cnt, len;
|
||||
|
||||
// Data from OPAL-RT model
|
||||
double mdldata[MAX_VALUES];
|
||||
int mdldata_size;
|
||||
// Data from OPAL-RT model
|
||||
double mdldata[MAX_VALUES];
|
||||
int mdldata_size;
|
||||
|
||||
#if PROTOCOL == VILLAS
|
||||
char buf[MSG_LEN(MAX_VALUES)];
|
||||
struct msg *msg = (struct msg *) buf;
|
||||
char buf[MSG_LEN(MAX_VALUES)];
|
||||
struct msg *msg = (struct msg *)buf;
|
||||
#elif PROTOCOL == GTNET_SKT
|
||||
char buf[MAX_VALUES * sizeof(float)];
|
||||
float *msg = (float *) buf;
|
||||
char buf[MAX_VALUES * sizeof(float)];
|
||||
float *msg = (float *)buf;
|
||||
#endif
|
||||
|
||||
OpalPrint("%s: SendToIPPort thread started\n", PROGNAME);
|
||||
OpalPrint("%s: SendToIPPort thread started\n", PROGNAME);
|
||||
|
||||
OpalGetNbAsyncSendIcon(&nbSend);
|
||||
if (nbSend < 1) {
|
||||
OpalPrint("%s: SendToIPPort: No transimission block for this controller. Stopping thread.\n", PROGNAME);
|
||||
return NULL;
|
||||
}
|
||||
OpalGetNbAsyncSendIcon(&nbSend);
|
||||
if (nbSend < 1) {
|
||||
OpalPrint("%s: SendToIPPort: No transimission block for this controller. "
|
||||
"Stopping thread.\n",
|
||||
PROGNAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
// This call unblocks when the 'Data Ready' line of a send icon is asserted.
|
||||
ret = OpalWaitForAsyncSendRequest(&SendID);
|
||||
if (ret != EOK) {
|
||||
ModelState = OpalGetAsyncModelState();
|
||||
if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) {
|
||||
OpalSetAsyncSendIconError(ret, SendID);
|
||||
OpalPrint("%s: OpalWaitForAsyncSendRequest(), errno %d\n", PROGNAME, ret);
|
||||
}
|
||||
do {
|
||||
// This call unblocks when the 'Data Ready' line of a send icon is asserted.
|
||||
ret = OpalWaitForAsyncSendRequest(&SendID);
|
||||
if (ret != EOK) {
|
||||
ModelState = OpalGetAsyncModelState();
|
||||
if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) {
|
||||
OpalSetAsyncSendIconError(ret, SendID);
|
||||
OpalPrint("%s: OpalWaitForAsyncSendRequest(), errno %d\n", PROGNAME,
|
||||
ret);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// No errors encountered yet
|
||||
OpalSetAsyncSendIconError(0, SendID);
|
||||
// No errors encountered yet
|
||||
OpalSetAsyncSendIconError(0, SendID);
|
||||
|
||||
// Get the size of the data being sent by the unblocking SendID
|
||||
OpalGetAsyncSendIconDataLength(&mdldata_size, SendID);
|
||||
cnt = mdldata_size / sizeof(double);
|
||||
if (cnt > MAX_VALUES) {
|
||||
OpalPrint("%s: Number of signals for SendID=%d exceeds allowed maximum (%d). Limiting...\n",
|
||||
PROGNAME, SendID, MAX_VALUES);
|
||||
cnt = MAX_VALUES;
|
||||
}
|
||||
// Get the size of the data being sent by the unblocking SendID
|
||||
OpalGetAsyncSendIconDataLength(&mdldata_size, SendID);
|
||||
cnt = mdldata_size / sizeof(double);
|
||||
if (cnt > MAX_VALUES) {
|
||||
OpalPrint("%s: Number of signals for SendID=%d exceeds allowed maximum "
|
||||
"(%d). Limiting...\n",
|
||||
PROGNAME, SendID, MAX_VALUES);
|
||||
cnt = MAX_VALUES;
|
||||
}
|
||||
|
||||
// Read data from the model
|
||||
OpalGetAsyncSendIconData(mdldata, mdldata_size, SendID);
|
||||
// Read data from the model
|
||||
OpalGetAsyncSendIconData(mdldata, mdldata_size, SendID);
|
||||
|
||||
#if PROTOCOL == VILLAS
|
||||
// Get current time
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
// Get current time
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
|
||||
msg->version = MSG_VERSION;
|
||||
msg->type = MSG_TYPE_DATA;
|
||||
msg->reserved1 = 0;
|
||||
msg->id = SendID;
|
||||
msg->length = cnt;
|
||||
msg->sequence = Sequence++;
|
||||
msg->ts.sec = now.tv_sec;
|
||||
msg->ts.nsec = now.tv_nsec;
|
||||
msg->version = MSG_VERSION;
|
||||
msg->type = MSG_TYPE_DATA;
|
||||
msg->reserved1 = 0;
|
||||
msg->id = SendID;
|
||||
msg->length = cnt;
|
||||
msg->sequence = Sequence++;
|
||||
msg->ts.sec = now.tv_sec;
|
||||
msg->ts.nsec = now.tv_nsec;
|
||||
|
||||
for (int i = 0; i < msg->length; i++)
|
||||
msg->data[i].f = (float) mdldata[i];
|
||||
for (int i = 0; i < msg->length; i++)
|
||||
msg->data[i].f = (float)mdldata[i];
|
||||
|
||||
len = MSG_LEN(msg->length);
|
||||
len = MSG_LEN(msg->length);
|
||||
|
||||
msg_hton(msg);
|
||||
msg_hton(msg);
|
||||
#elif PROTOCOL == GTNET_SKT
|
||||
uint32_t *imsg = (uint32_t *) msg;
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
msg[i] = (float) mdldata[i];
|
||||
imsg[i] = htonl(imsg[i]);
|
||||
}
|
||||
uint32_t *imsg = (uint32_t *)msg;
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
msg[i] = (float)mdldata[i];
|
||||
imsg[i] = htonl(imsg[i]);
|
||||
}
|
||||
|
||||
len = cnt * sizeof(float);
|
||||
len = cnt * sizeof(float);
|
||||
#else
|
||||
#error Unknown protocol
|
||||
#error Unknown protocol
|
||||
#endif
|
||||
|
||||
// Perform the actual write to the ip port
|
||||
ret = socket_send(&skt, (char *) msg, len);
|
||||
if (ret < 0)
|
||||
OpalSetAsyncSendIconError(errno, SendID);
|
||||
else
|
||||
OpalSetAsyncSendIconError(0, SendID);
|
||||
// Perform the actual write to the ip port
|
||||
ret = socket_send(&skt, (char *)msg, len);
|
||||
if (ret < 0)
|
||||
OpalSetAsyncSendIconError(errno, SendID);
|
||||
else
|
||||
OpalSetAsyncSendIconError(0, SendID);
|
||||
|
||||
/* This next call allows the execution of the "asynchronous" process
|
||||
/* This next call allows the execution of the "asynchronous" process
|
||||
* to actually be synchronous with the model. To achieve this, you
|
||||
* should set the "Sending Mode" in the Async_Send block to
|
||||
* NEED_REPLY_BEFORE_NEXT_SEND or NEED_REPLY_NOW. This will force
|
||||
* the model to wait for this process to call this
|
||||
* OpalAsyncSendRequestDone function before continuing. */
|
||||
OpalAsyncSendRequestDone(SendID);
|
||||
OpalAsyncSendRequestDone(SendID);
|
||||
|
||||
/* Before continuing, we make sure that the real-time model
|
||||
/* Before continuing, we make sure that the real-time model
|
||||
* has not been stopped. If it has, we quit. */
|
||||
ModelState = OpalGetAsyncModelState();
|
||||
} while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));
|
||||
ModelState = OpalGetAsyncModelState();
|
||||
} while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));
|
||||
|
||||
OpalPrint("%s: SendToIPPort: Finished\n", PROGNAME);
|
||||
OpalPrint("%s: SendToIPPort: Finished\n", PROGNAME);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void * RecvFromIPPort(void *arg)
|
||||
{
|
||||
unsigned int ModelState, RecvID;
|
||||
int nbRecv = 0, ret, cnt;
|
||||
static void *RecvFromIPPort(void *arg) {
|
||||
unsigned int ModelState, RecvID;
|
||||
int nbRecv = 0, ret, cnt;
|
||||
|
||||
// Data from OPAL-RT model
|
||||
double mdldata[MAX_VALUES];
|
||||
int mdldata_size;
|
||||
// Data from OPAL-RT model
|
||||
double mdldata[MAX_VALUES];
|
||||
int mdldata_size;
|
||||
|
||||
#if PROTOCOL == VILLAS
|
||||
char buf[MSG_LEN(MAX_VALUES)];
|
||||
struct msg *msg = (struct msg *) buf;
|
||||
char buf[MSG_LEN(MAX_VALUES)];
|
||||
struct msg *msg = (struct msg *)buf;
|
||||
#elif PROTOCOL == GTNET_SKT
|
||||
char buf[MAX_VALUES * sizeof(float)];
|
||||
float *msg = (float *) buf;
|
||||
char buf[MAX_VALUES * sizeof(float)];
|
||||
float *msg = (float *)buf;
|
||||
#else
|
||||
#error Unknown protocol
|
||||
#error Unknown protocol
|
||||
#endif
|
||||
|
||||
OpalPrint("%s: RecvFromIPPort thread started\n", PROGNAME);
|
||||
OpalPrint("%s: RecvFromIPPort thread started\n", PROGNAME);
|
||||
|
||||
OpalGetNbAsyncRecvIcon(&nbRecv);
|
||||
if (nbRecv < 1) {
|
||||
OpalPrint("%s: RecvFromIPPort: No reception block for this controller. Stopping thread.\n", PROGNAME);
|
||||
return NULL;
|
||||
}
|
||||
OpalGetNbAsyncRecvIcon(&nbRecv);
|
||||
if (nbRecv < 1) {
|
||||
OpalPrint("%s: RecvFromIPPort: No reception block for this controller. "
|
||||
"Stopping thread.\n",
|
||||
PROGNAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get list of RecvIds
|
||||
unsigned int RecvIDs[nbRecv];
|
||||
ret = OpalGetAsyncRecvIDList(RecvIDs, sizeof(RecvIDs));
|
||||
if (ret != EOK) {
|
||||
OpalPrint("%s: Failed to get list of RecvIDs\n", PROGNAME);
|
||||
return NULL;
|
||||
}
|
||||
// Get list of RecvIds
|
||||
unsigned int RecvIDs[nbRecv];
|
||||
ret = OpalGetAsyncRecvIDList(RecvIDs, sizeof(RecvIDs));
|
||||
if (ret != EOK) {
|
||||
OpalPrint("%s: Failed to get list of RecvIDs\n", PROGNAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
// Receive message
|
||||
ret = socket_recv(&skt, (char *) msg, sizeof(buf), 1.0);
|
||||
if (ret < 1) {
|
||||
ModelState = OpalGetAsyncModelState();
|
||||
if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) {
|
||||
if (ret == 0) // timeout, so we continue silently
|
||||
OpalPrint("%s: Timeout while waiting for data\n", PROGNAME, errno);
|
||||
if (ret == -1) // a more serious error, so we print it
|
||||
OpalPrint("%s: Error %d while waiting for data\n", PROGNAME, errno);
|
||||
do {
|
||||
// Receive message
|
||||
ret = socket_recv(&skt, (char *)msg, sizeof(buf), 1.0);
|
||||
if (ret < 1) {
|
||||
ModelState = OpalGetAsyncModelState();
|
||||
if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) {
|
||||
if (ret == 0) // timeout, so we continue silently
|
||||
OpalPrint("%s: Timeout while waiting for data\n", PROGNAME, errno);
|
||||
if (ret == -1) // a more serious error, so we print it
|
||||
OpalPrint("%s: Error %d while waiting for data\n", PROGNAME, errno);
|
||||
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#if PROTOCOL == VILLAS
|
||||
RecvID = msg->id;
|
||||
RecvID = msg->id;
|
||||
#elif PROTOCOL == GTNET_SKT
|
||||
RecvID = 1;
|
||||
RecvID = 1;
|
||||
#else
|
||||
#error Unknown protocol
|
||||
#error Unknown protocol
|
||||
#endif
|
||||
// Check if this RecvID exists
|
||||
for (int i = 0; i < nbRecv; i++) {
|
||||
if (RecvIDs[i] == RecvID)
|
||||
goto found;
|
||||
}
|
||||
// Check if this RecvID exists
|
||||
for (int i = 0; i < nbRecv; i++) {
|
||||
if (RecvIDs[i] == RecvID)
|
||||
goto found;
|
||||
}
|
||||
|
||||
OpalPrint("%s: Received message with non-existent RecvID=%d. Changing to RecvID=%d...\n", PROGNAME, RecvID, RecvIDs[0]);
|
||||
RecvID = RecvIDs[0];
|
||||
OpalPrint("%s: Received message with non-existent RecvID=%d. Changing to "
|
||||
"RecvID=%d...\n",
|
||||
PROGNAME, RecvID, RecvIDs[0]);
|
||||
RecvID = RecvIDs[0];
|
||||
|
||||
found: // Get the number of signals to send back to the model
|
||||
OpalGetAsyncRecvIconDataLength(&mdldata_size, RecvID);
|
||||
cnt = mdldata_size / sizeof(double);
|
||||
if (cnt > MAX_VALUES) {
|
||||
OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds allowed maximum (%d)\n",
|
||||
PROGNAME, RecvID, cnt, MAX_VALUES);
|
||||
return NULL;
|
||||
}
|
||||
found: // Get the number of signals to send back to the model
|
||||
OpalGetAsyncRecvIconDataLength(&mdldata_size, RecvID);
|
||||
cnt = mdldata_size / sizeof(double);
|
||||
if (cnt > MAX_VALUES) {
|
||||
OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds allowed "
|
||||
"maximum (%d)\n",
|
||||
PROGNAME, RecvID, cnt, MAX_VALUES);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if PROTOCOL == VILLAS
|
||||
msg_ntoh(msg);
|
||||
msg_ntoh(msg);
|
||||
|
||||
ret = msg_verify(msg);
|
||||
if (ret) {
|
||||
OpalPrint("%s: Skipping invalid packet\n", PROGNAME);
|
||||
continue;
|
||||
}
|
||||
ret = msg_verify(msg);
|
||||
if (ret) {
|
||||
OpalPrint("%s: Skipping invalid packet\n", PROGNAME);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cnt > msg->length) {
|
||||
OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds what was received (%d)\n",
|
||||
PROGNAME, RecvID, cnt, msg->length);
|
||||
}
|
||||
if (cnt > msg->length) {
|
||||
OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds what was "
|
||||
"received (%d)\n",
|
||||
PROGNAME, RecvID, cnt, msg->length);
|
||||
}
|
||||
|
||||
for (int i = 0; i < msg->length; i++)
|
||||
mdldata[i] = (double) msg->data[i].f;
|
||||
for (int i = 0; i < msg->length; i++)
|
||||
mdldata[i] = (double)msg->data[i].f;
|
||||
|
||||
// Update OPAL model
|
||||
OpalSetAsyncRecvIconStatus(msg->sequence, RecvID); // Set the Status to the message ID
|
||||
// Update OPAL model
|
||||
OpalSetAsyncRecvIconStatus(msg->sequence,
|
||||
RecvID); // Set the Status to the message ID
|
||||
#elif PROTOCOL == GTNET_SKT
|
||||
uint32_t *imsg = (uint32_t *) msg;
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
imsg[i] = ntohl(imsg[i]);
|
||||
mdldata[i] = (double) msg[i];
|
||||
}
|
||||
uint32_t *imsg = (uint32_t *)msg;
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
imsg[i] = ntohl(imsg[i]);
|
||||
mdldata[i] = (double)msg[i];
|
||||
}
|
||||
#else
|
||||
#error Unknown protocol
|
||||
#error Unknown protocol
|
||||
#endif
|
||||
|
||||
OpalSetAsyncRecvIconError(0, RecvID); // Set the Error to 0
|
||||
OpalSetAsyncRecvIconError(0, RecvID); // Set the Error to 0
|
||||
|
||||
OpalSetAsyncRecvIconData(mdldata, mdldata_size, RecvID);
|
||||
OpalSetAsyncRecvIconData(mdldata, mdldata_size, RecvID);
|
||||
|
||||
/* Before continuing, we make sure that the real-time model
|
||||
/* Before continuing, we make sure that the real-time model
|
||||
* has not been stopped. If it has, we quit. */
|
||||
ModelState = OpalGetAsyncModelState();
|
||||
} while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));
|
||||
ModelState = OpalGetAsyncModelState();
|
||||
} while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));
|
||||
|
||||
OpalPrint("%s: RecvFromIPPort: Finished\n", PROGNAME);
|
||||
OpalPrint("%s: RecvFromIPPort: Finished\n", PROGNAME);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
int main(int argc, char *argv[]) {
|
||||
int ret;
|
||||
|
||||
Opal_GenAsyncParam_Ctrl IconCtrlStruct;
|
||||
Opal_GenAsyncParam_Ctrl IconCtrlStruct;
|
||||
|
||||
pthread_t tid_send, tid_recv;
|
||||
pthread_t tid_send, tid_recv;
|
||||
|
||||
OpalPrint("%s: This is %s client version %s\n", PROGNAME, PROGNAME, VERSION);
|
||||
OpalPrint("%s: This is %s client version %s\n", PROGNAME, PROGNAME, VERSION);
|
||||
|
||||
// Check for the proper arguments to the program
|
||||
if (argc < 4) {
|
||||
printf("Invalid Arguments: 1-AsyncShmemName 2-AsyncShmemSize 3-PrintShmemName\n");
|
||||
exit(0);
|
||||
}
|
||||
// Check for the proper arguments to the program
|
||||
if (argc < 4) {
|
||||
printf("Invalid Arguments: 1-AsyncShmemName 2-AsyncShmemSize "
|
||||
"3-PrintShmemName\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Enable the OpalPrint function. This prints to the OpalDisplay.
|
||||
ret = OpalSystemCtrl_Register(PRINT_SHMEM_NAME);
|
||||
if (ret != EOK) {
|
||||
printf("%s: ERROR: OpalPrint() access not available\n", PROGNAME);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Enable the OpalPrint function. This prints to the OpalDisplay.
|
||||
ret = OpalSystemCtrl_Register(PRINT_SHMEM_NAME);
|
||||
if (ret != EOK) {
|
||||
printf("%s: ERROR: OpalPrint() access not available\n", PROGNAME);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Open Share Memory created by the model.
|
||||
ret = OpalOpenAsyncMem(ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME);
|
||||
if (ret != EOK) {
|
||||
OpalPrint("%s: ERROR: Model shared memory not available\n", PROGNAME);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Open Share Memory created by the model.
|
||||
ret = OpalOpenAsyncMem(ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME);
|
||||
if (ret != EOK) {
|
||||
OpalPrint("%s: ERROR: Model shared memory not available\n", PROGNAME);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
AssignProcToCpu0();
|
||||
AssignProcToCpu0();
|
||||
|
||||
/* Get IP Controler Parameters (ie: ip address, port number...) and
|
||||
/* Get IP Controler Parameters (ie: ip address, port number...) and
|
||||
* initialize the device on the QNX node. */
|
||||
memset(&IconCtrlStruct, 0, sizeof(IconCtrlStruct));
|
||||
memset(&IconCtrlStruct, 0, sizeof(IconCtrlStruct));
|
||||
|
||||
ret = OpalGetAsyncCtrlParameters(&IconCtrlStruct, sizeof(IconCtrlStruct));
|
||||
if (ret != EOK) {
|
||||
OpalPrint("%s: ERROR: Could not get controller parameters (%d).\n", PROGNAME, ret);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ret = OpalGetAsyncCtrlParameters(&IconCtrlStruct, sizeof(IconCtrlStruct));
|
||||
if (ret != EOK) {
|
||||
OpalPrint("%s: ERROR: Could not get controller parameters (%d).\n",
|
||||
PROGNAME, ret);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Initialize socket
|
||||
ret = socket_init(&skt, IconCtrlStruct);
|
||||
if (ret != EOK) {
|
||||
OpalPrint("%s: ERROR: Failed to create socket.\n", PROGNAME);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Initialize socket
|
||||
ret = socket_init(&skt, IconCtrlStruct);
|
||||
if (ret != EOK) {
|
||||
OpalPrint("%s: ERROR: Failed to create socket.\n", PROGNAME);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Start send/receive threads
|
||||
ret = pthread_create(&tid_send, NULL, SendToIPPort, NULL);
|
||||
if (ret < 0)
|
||||
OpalPrint("%s: ERROR: Could not create thread (SendToIPPort), errno %d\n", PROGNAME, errno);
|
||||
// Start send/receive threads
|
||||
ret = pthread_create(&tid_send, NULL, SendToIPPort, NULL);
|
||||
if (ret < 0)
|
||||
OpalPrint("%s: ERROR: Could not create thread (SendToIPPort), errno %d\n",
|
||||
PROGNAME, errno);
|
||||
|
||||
ret = pthread_create(&tid_recv, NULL, RecvFromIPPort, NULL);
|
||||
if (ret < 0)
|
||||
OpalPrint("%s: ERROR: Could not create thread (RecvFromIPPort), errno %d\n", PROGNAME, errno);
|
||||
ret = pthread_create(&tid_recv, NULL, RecvFromIPPort, NULL);
|
||||
if (ret < 0)
|
||||
OpalPrint("%s: ERROR: Could not create thread (RecvFromIPPort), errno %d\n",
|
||||
PROGNAME, errno);
|
||||
|
||||
// Wait for both threads to finish
|
||||
ret = pthread_join(tid_send, NULL);
|
||||
if (ret)
|
||||
OpalPrint("%s: ERROR: pthread_join (SendToIPPort), errno %d\n", PROGNAME, ret);
|
||||
// Wait for both threads to finish
|
||||
ret = pthread_join(tid_send, NULL);
|
||||
if (ret)
|
||||
OpalPrint("%s: ERROR: pthread_join (SendToIPPort), errno %d\n", PROGNAME,
|
||||
ret);
|
||||
|
||||
ret = pthread_join(tid_recv, NULL);
|
||||
if (ret)
|
||||
OpalPrint("%s: ERROR: pthread_join (RecvFromIPPort), errno %d\n", PROGNAME, ret);
|
||||
ret = pthread_join(tid_recv, NULL);
|
||||
if (ret)
|
||||
OpalPrint("%s: ERROR: pthread_join (RecvFromIPPort), errno %d\n", PROGNAME,
|
||||
ret);
|
||||
|
||||
// Close the ip port and shared memories
|
||||
socket_close(&skt, IconCtrlStruct);
|
||||
// Close the ip port and shared memories
|
||||
socket_close(&skt, IconCtrlStruct);
|
||||
|
||||
OpalCloseAsyncMem (ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME);
|
||||
OpalSystemCtrl_UnRegister(PRINT_SHMEM_NAME);
|
||||
OpalCloseAsyncMem(ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME);
|
||||
OpalSystemCtrl_UnRegister(PRINT_SHMEM_NAME);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,46 +10,41 @@
|
|||
#include "msg.h"
|
||||
#include "msg_format.h"
|
||||
|
||||
void msg_ntoh(struct msg *m)
|
||||
{
|
||||
msg_hdr_ntoh(m);
|
||||
void msg_ntoh(struct msg *m) {
|
||||
msg_hdr_ntoh(m);
|
||||
|
||||
for (int i = 0; i < m->length; i++)
|
||||
m->data[i].i = ntohl(m->data[i].i);
|
||||
for (int i = 0; i < m->length; i++)
|
||||
m->data[i].i = ntohl(m->data[i].i);
|
||||
}
|
||||
|
||||
void msg_hton(struct msg *m)
|
||||
{
|
||||
for (int i = 0; i < m->length; i++)
|
||||
m->data[i].i = htonl(m->data[i].i);
|
||||
void msg_hton(struct msg *m) {
|
||||
for (int i = 0; i < m->length; i++)
|
||||
m->data[i].i = htonl(m->data[i].i);
|
||||
|
||||
msg_hdr_hton(m);
|
||||
msg_hdr_hton(m);
|
||||
}
|
||||
|
||||
void msg_hdr_hton(struct msg *m)
|
||||
{
|
||||
m->length = htons(m->length);
|
||||
m->sequence = htonl(m->sequence);
|
||||
m->ts.sec = htonl(m->ts.sec);
|
||||
m->ts.nsec = htonl(m->ts.nsec);
|
||||
void msg_hdr_hton(struct msg *m) {
|
||||
m->length = htons(m->length);
|
||||
m->sequence = htonl(m->sequence);
|
||||
m->ts.sec = htonl(m->ts.sec);
|
||||
m->ts.nsec = htonl(m->ts.nsec);
|
||||
}
|
||||
|
||||
void msg_hdr_ntoh(struct msg *m)
|
||||
{
|
||||
m->length = ntohs(m->length);
|
||||
m->sequence = ntohl(m->sequence);
|
||||
m->ts.sec = ntohl(m->ts.sec);
|
||||
m->ts.nsec = ntohl(m->ts.nsec);
|
||||
void msg_hdr_ntoh(struct msg *m) {
|
||||
m->length = ntohs(m->length);
|
||||
m->sequence = ntohl(m->sequence);
|
||||
m->ts.sec = ntohl(m->ts.sec);
|
||||
m->ts.nsec = ntohl(m->ts.nsec);
|
||||
}
|
||||
|
||||
int msg_verify(struct msg *m)
|
||||
{
|
||||
if (m->version != MSG_VERSION)
|
||||
return -1;
|
||||
else if (m->type != MSG_TYPE_DATA)
|
||||
return -2;
|
||||
else if (m->reserved1 != 0)
|
||||
return -3;
|
||||
else
|
||||
return 0;
|
||||
int msg_verify(struct msg *m) {
|
||||
if (m->version != MSG_VERSION)
|
||||
return -1;
|
||||
else if (m->type != MSG_TYPE_DATA)
|
||||
return -2;
|
||||
else if (m->reserved1 != 0)
|
||||
return -3;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,165 +5,177 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Define RTLAB before including OpalPrint.h for messages to be sent
|
||||
* to the OpalDisplay. Otherwise stdout will be used. */
|
||||
#define RTLAB
|
||||
#include "OpalPrint.h"
|
||||
#include "AsyncApi.h"
|
||||
#include "OpalPrint.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "socket.h"
|
||||
|
||||
int socket_init(struct socket *s, Opal_GenAsyncParam_Ctrl IconCtrlStruct)
|
||||
{
|
||||
struct ip_mreq mreq; // Multicast group structure
|
||||
unsigned char TTL = 1, LOOP = 0;
|
||||
int rc, proto, ret;
|
||||
int socket_init(struct socket *s, Opal_GenAsyncParam_Ctrl IconCtrlStruct) {
|
||||
struct ip_mreq mreq; // Multicast group structure
|
||||
unsigned char TTL = 1, LOOP = 0;
|
||||
int rc, proto, ret;
|
||||
|
||||
proto = (int) IconCtrlStruct.FloatParam[0];
|
||||
if (proto != UDP_PROTOCOL) {
|
||||
OpalPrint("%s: This version of %s only supports UDP\n", PROGNAME, PROGNAME);
|
||||
return EIO;
|
||||
}
|
||||
proto = (int)IconCtrlStruct.FloatParam[0];
|
||||
if (proto != UDP_PROTOCOL) {
|
||||
OpalPrint("%s: This version of %s only supports UDP\n", PROGNAME, PROGNAME);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
OpalPrint("%s: Version : %s\n", PROGNAME, VERSION);
|
||||
OpalPrint("%s: Remote Address : %s\n", PROGNAME, IconCtrlStruct.StringParam[0]);
|
||||
OpalPrint("%s: Remote Port : %d\n", PROGNAME, (int) IconCtrlStruct.FloatParam[1]);
|
||||
OpalPrint("%s: Version : %s\n", PROGNAME, VERSION);
|
||||
OpalPrint("%s: Remote Address : %s\n", PROGNAME,
|
||||
IconCtrlStruct.StringParam[0]);
|
||||
OpalPrint("%s: Remote Port : %d\n", PROGNAME,
|
||||
(int)IconCtrlStruct.FloatParam[1]);
|
||||
|
||||
// Initialize the socket
|
||||
s->sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s->sd < 0) {
|
||||
OpalPrint("%s: ERROR: Could not open socket\n", PROGNAME);
|
||||
return EIO;
|
||||
}
|
||||
// Initialize the socket
|
||||
s->sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s->sd < 0) {
|
||||
OpalPrint("%s: ERROR: Could not open socket\n", PROGNAME);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
// Set the structure for the remote port and address
|
||||
memset(&s->send_ad, 0, sizeof(s->send_ad));
|
||||
s->send_ad.sin_family = AF_INET;
|
||||
s->send_ad.sin_addr.s_addr = inet_addr(IconCtrlStruct.StringParam[0]);
|
||||
s->send_ad.sin_port = htons((u_short) IconCtrlStruct.FloatParam[1]);
|
||||
// Set the structure for the remote port and address
|
||||
memset(&s->send_ad, 0, sizeof(s->send_ad));
|
||||
s->send_ad.sin_family = AF_INET;
|
||||
s->send_ad.sin_addr.s_addr = inet_addr(IconCtrlStruct.StringParam[0]);
|
||||
s->send_ad.sin_port = htons((u_short)IconCtrlStruct.FloatParam[1]);
|
||||
|
||||
// Set the structure for the local port and address
|
||||
memset(&s->recv_ad, 0, sizeof(s->recv_ad));
|
||||
s->recv_ad.sin_family = AF_INET;
|
||||
s->recv_ad.sin_addr.s_addr = INADDR_ANY;
|
||||
s->recv_ad.sin_port = htons((u_short) IconCtrlStruct.FloatParam[2]);
|
||||
// Set the structure for the local port and address
|
||||
memset(&s->recv_ad, 0, sizeof(s->recv_ad));
|
||||
s->recv_ad.sin_family = AF_INET;
|
||||
s->recv_ad.sin_addr.s_addr = INADDR_ANY;
|
||||
s->recv_ad.sin_port = htons((u_short)IconCtrlStruct.FloatParam[2]);
|
||||
|
||||
// Bind local port and address to socket.
|
||||
ret = bind(s->sd, (struct sockaddr *) &s->recv_ad, sizeof(struct sockaddr_in));
|
||||
if (ret < 0) {
|
||||
OpalPrint("%s: ERROR: Could not bind local port to socket\n", PROGNAME);
|
||||
return EIO;
|
||||
}
|
||||
else
|
||||
OpalPrint("%s: Local Port : %d\n", PROGNAME, (int) IconCtrlStruct.FloatParam[2]);
|
||||
// Bind local port and address to socket.
|
||||
ret = bind(s->sd, (struct sockaddr *)&s->recv_ad, sizeof(struct sockaddr_in));
|
||||
if (ret < 0) {
|
||||
OpalPrint("%s: ERROR: Could not bind local port to socket\n", PROGNAME);
|
||||
return EIO;
|
||||
} else
|
||||
OpalPrint("%s: Local Port : %d\n", PROGNAME,
|
||||
(int)IconCtrlStruct.FloatParam[2]);
|
||||
|
||||
// If sending to a multicast address
|
||||
if ((inet_addr(IconCtrlStruct.StringParam[0]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) {
|
||||
ret = setsockopt(s->sd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &TTL, sizeof(TTL));
|
||||
if (ret == -1) {
|
||||
OpalPrint("%s: ERROR: Could not set TTL for multicast send (%d)\n", PROGNAME, errno);
|
||||
return EIO;
|
||||
}
|
||||
// If sending to a multicast address
|
||||
if ((inet_addr(IconCtrlStruct.StringParam[0]) & inet_addr("240.0.0.0")) ==
|
||||
inet_addr("224.0.0.0")) {
|
||||
ret = setsockopt(s->sd, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&TTL,
|
||||
sizeof(TTL));
|
||||
if (ret == -1) {
|
||||
OpalPrint("%s: ERROR: Could not set TTL for multicast send (%d)\n",
|
||||
PROGNAME, errno);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
ret = setsockopt(s->sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&LOOP, sizeof(LOOP));
|
||||
if (ret == -1) {
|
||||
OpalPrint("%s: ERROR: Could not set loopback for multicast send (%d)\n", PROGNAME, errno);
|
||||
return EIO;
|
||||
}
|
||||
ret = setsockopt(s->sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&LOOP,
|
||||
sizeof(LOOP));
|
||||
if (ret == -1) {
|
||||
OpalPrint("%s: ERROR: Could not set loopback for multicast send (%d)\n",
|
||||
PROGNAME, errno);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
OpalPrint("%s: Configured socket for sending to multicast address\n", PROGNAME);
|
||||
}
|
||||
OpalPrint("%s: Configured socket for sending to multicast address\n",
|
||||
PROGNAME);
|
||||
}
|
||||
|
||||
// If receiving from a multicast group, register for it.
|
||||
if (inet_addr(IconCtrlStruct.StringParam[1]) > 0) {
|
||||
if ((inet_addr(IconCtrlStruct.StringParam[1]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) {
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(IconCtrlStruct.StringParam[1]);
|
||||
mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
// If receiving from a multicast group, register for it.
|
||||
if (inet_addr(IconCtrlStruct.StringParam[1]) > 0) {
|
||||
if ((inet_addr(IconCtrlStruct.StringParam[1]) & inet_addr("240.0.0.0")) ==
|
||||
inet_addr("224.0.0.0")) {
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(IconCtrlStruct.StringParam[1]);
|
||||
mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
|
||||
// Have the multicast socket join the multicast group
|
||||
ret = setsockopt(s->sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq));
|
||||
if (ret == -1) {
|
||||
OpalPrint("%s: ERROR: Could not join multicast group (%d)\n", PROGNAME, errno);
|
||||
return EIO;
|
||||
}
|
||||
// Have the multicast socket join the multicast group
|
||||
ret = setsockopt(s->sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq,
|
||||
sizeof(mreq));
|
||||
if (ret == -1) {
|
||||
OpalPrint("%s: ERROR: Could not join multicast group (%d)\n", PROGNAME,
|
||||
errno);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
OpalPrint("%s: Added process to multicast group (%s)\n", PROGNAME, IconCtrlStruct.StringParam[1]);
|
||||
}
|
||||
else
|
||||
OpalPrint("%s: WARNING: IP address for multicast group is not in multicast range. Ignored\n", PROGNAME);
|
||||
}
|
||||
OpalPrint("%s: Added process to multicast group (%s)\n", PROGNAME,
|
||||
IconCtrlStruct.StringParam[1]);
|
||||
} else
|
||||
OpalPrint("%s: WARNING: IP address for multicast group is not in "
|
||||
"multicast range. Ignored\n",
|
||||
PROGNAME);
|
||||
}
|
||||
|
||||
return EOK;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
int socket_close(struct socket *s, Opal_GenAsyncParam_Ctrl IconCtrlStruct)
|
||||
{
|
||||
int ret;
|
||||
int socket_close(struct socket *s, Opal_GenAsyncParam_Ctrl IconCtrlStruct) {
|
||||
int ret;
|
||||
|
||||
ret = shutdown(s->sd, SHUT_RDWR);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = shutdown(s->sd, SHUT_RDWR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = close(s->sd);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = close(s->sd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_send(struct socket *s, char *data, int len)
|
||||
{
|
||||
return sendto(s->sd, data, len, 0, (struct sockaddr *) &s->send_ad, sizeof(s->send_ad));
|
||||
int socket_send(struct socket *s, char *data, int len) {
|
||||
return sendto(s->sd, data, len, 0, (struct sockaddr *)&s->send_ad,
|
||||
sizeof(s->send_ad));
|
||||
}
|
||||
|
||||
int socket_recv(struct socket *s, char *data, int len, double timeout)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr_in client_ad;
|
||||
struct timeval tv;
|
||||
socklen_t client_ad_size = sizeof(client_ad);
|
||||
fd_set sd_set;
|
||||
int socket_recv(struct socket *s, char *data, int len, double timeout) {
|
||||
int ret;
|
||||
struct sockaddr_in client_ad;
|
||||
struct timeval tv;
|
||||
socklen_t client_ad_size = sizeof(client_ad);
|
||||
fd_set sd_set;
|
||||
|
||||
// Set the descriptor set for the select() call
|
||||
FD_ZERO(&sd_set);
|
||||
FD_SET(s->sd, &sd_set);
|
||||
// Set the descriptor set for the select() call
|
||||
FD_ZERO(&sd_set);
|
||||
FD_SET(s->sd, &sd_set);
|
||||
|
||||
// Set the tv structure to the correct timeout value
|
||||
tv.tv_sec = (int) timeout;
|
||||
tv.tv_usec = (int) ((timeout - tv.tv_sec) * 1000000);
|
||||
// Set the tv structure to the correct timeout value
|
||||
tv.tv_sec = (int)timeout;
|
||||
tv.tv_usec = (int)((timeout - tv.tv_sec) * 1000000);
|
||||
|
||||
/* Wait for a packet. We use select() to have a timeout. This is
|
||||
/* Wait for a packet. We use select() to have a timeout. This is
|
||||
* necessary when reseting the model so we don't wait indefinitely
|
||||
* and prevent the process from exiting and freeing the port for
|
||||
* a future instance (model load). */
|
||||
ret = select(s->sd + 1, &sd_set, (fd_set *) 0, (fd_set *) 0, &tv);
|
||||
switch (ret) {
|
||||
case -1: // Error
|
||||
return -1;
|
||||
case 0: // We hit the timeout
|
||||
return 0;
|
||||
default:
|
||||
if (!(FD_ISSET(s->sd, &sd_set))) {
|
||||
/* We received something, but it's not on "sd". Since sd is the only
|
||||
ret = select(s->sd + 1, &sd_set, (fd_set *)0, (fd_set *)0, &tv);
|
||||
switch (ret) {
|
||||
case -1: // Error
|
||||
return -1;
|
||||
case 0: // We hit the timeout
|
||||
return 0;
|
||||
default:
|
||||
if (!(FD_ISSET(s->sd, &sd_set))) {
|
||||
/* We received something, but it's not on "sd". Since sd is the only
|
||||
* descriptor in the set... */
|
||||
OpalPrint("%s: RecvPacket: God, is that You trying to reach me?\n", PROGNAME);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
OpalPrint("%s: RecvPacket: God, is that You trying to reach me?\n",
|
||||
PROGNAME);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the data array (in case we receive an incomplete packet)
|
||||
memset(data, 0, len);
|
||||
// Clear the data array (in case we receive an incomplete packet)
|
||||
memset(data, 0, len);
|
||||
|
||||
// Perform the reception
|
||||
return recvfrom(s->sd, data, len, 0, (struct sockaddr *) &client_ad, &client_ad_size);
|
||||
// Perform the reception
|
||||
return recvfrom(s->sd, data, len, 0, (struct sockaddr *)&client_ad,
|
||||
&client_ad_size);
|
||||
}
|
||||
|
|
|
@ -18,20 +18,19 @@
|
|||
#include "config.h"
|
||||
#include "utils.h"
|
||||
|
||||
int AssignProcToCpu0(void)
|
||||
{
|
||||
int ret;
|
||||
cpu_set_t bindSet;
|
||||
|
||||
CPU_ZERO(&bindSet);
|
||||
CPU_SET(0, &bindSet);
|
||||
int AssignProcToCpu0(void) {
|
||||
int ret;
|
||||
cpu_set_t bindSet;
|
||||
|
||||
// Changing process cpu affinity
|
||||
ret = sched_setaffinity(0, sizeof(cpu_set_t), &bindSet);
|
||||
if (ret) {
|
||||
OpalPrint("Unable to bind the process to CPU 0: %d\n", errno);
|
||||
return EINVAL;
|
||||
}
|
||||
CPU_ZERO(&bindSet);
|
||||
CPU_SET(0, &bindSet);
|
||||
|
||||
return 0;
|
||||
// Changing process cpu affinity
|
||||
ret = sched_setaffinity(0, sizeof(cpu_set_t), &bindSet);
|
||||
if (ret) {
|
||||
OpalPrint("Unable to bind the process to CPU 0: %d\n", errno);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/colors.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/node/exceptions.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/sample.hpp>
|
||||
#include <villas/shmem.hpp>
|
||||
#include <villas/colors.hpp>
|
||||
#include <villas/tool.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/utils.hpp>
|
||||
#include <villas/node/exceptions.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -29,101 +29,94 @@ namespace tools {
|
|||
class Shmem : public Tool {
|
||||
|
||||
public:
|
||||
Shmem(int argc, char *argv[]) :
|
||||
Tool(argc, argv, "shmem"),
|
||||
stop(false)
|
||||
{ }
|
||||
Shmem(int argc, char *argv[]) : Tool(argc, argv, "shmem"), stop(false) {}
|
||||
|
||||
protected:
|
||||
std::atomic<bool> stop;
|
||||
std::atomic<bool> stop;
|
||||
|
||||
void usage()
|
||||
{
|
||||
std::cout << "Usage: villas-test-shmem WNAME VECTORIZE" << std::endl
|
||||
<< " WNAME name of the shared memory object for the output queue" << std::endl
|
||||
<< " RNAME name of the shared memory object for the input queue" << std::endl
|
||||
<< " VECTORIZE maximum number of samples to read/write at a time" << std::endl;
|
||||
void usage() {
|
||||
std::cout
|
||||
<< "Usage: villas-test-shmem WNAME VECTORIZE" << std::endl
|
||||
<< " WNAME name of the shared memory object for the output queue"
|
||||
<< std::endl
|
||||
<< " RNAME name of the shared memory object for the input queue"
|
||||
<< std::endl
|
||||
<< " VECTORIZE maximum number of samples to read/write at a time"
|
||||
<< std::endl;
|
||||
|
||||
printCopyright();
|
||||
}
|
||||
printCopyright();
|
||||
}
|
||||
|
||||
void handler(int, siginfo_t *, void *)
|
||||
{
|
||||
stop = true;
|
||||
}
|
||||
void handler(int, siginfo_t *, void *) { stop = true; }
|
||||
|
||||
int main()
|
||||
{
|
||||
int ret, readcnt, writecnt, avail;
|
||||
int main() {
|
||||
int ret, readcnt, writecnt, avail;
|
||||
|
||||
struct ShmemInterface shm;
|
||||
struct ShmemConfig conf = {
|
||||
.polling = 0,
|
||||
.queuelen = DEFAULT_SHMEM_QUEUELEN,
|
||||
.samplelen = DEFAULT_SHMEM_SAMPLELEN
|
||||
};
|
||||
struct ShmemInterface shm;
|
||||
struct ShmemConfig conf = {.polling = 0,
|
||||
.queuelen = DEFAULT_SHMEM_QUEUELEN,
|
||||
.samplelen = DEFAULT_SHMEM_SAMPLELEN};
|
||||
|
||||
if (argc != 4) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if (argc != 4) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string wname = argv[1];
|
||||
std::string rname = argv[2];
|
||||
int vectorize = atoi(argv[3]);
|
||||
std::string wname = argv[1];
|
||||
std::string rname = argv[2];
|
||||
int vectorize = atoi(argv[3]);
|
||||
|
||||
ret = shmem_int_open(wname.c_str(), rname.c_str(), &shm, &conf);
|
||||
if (ret < 0)
|
||||
throw RuntimeError("Failed to open shared-memory interface");
|
||||
ret = shmem_int_open(wname.c_str(), rname.c_str(), &shm, &conf);
|
||||
if (ret < 0)
|
||||
throw RuntimeError("Failed to open shared-memory interface");
|
||||
|
||||
struct Sample *insmps[vectorize], *outsmps[vectorize];
|
||||
struct Sample *insmps[vectorize], *outsmps[vectorize];
|
||||
|
||||
while (!stop) {
|
||||
readcnt = shmem_int_read(&shm, insmps, vectorize);
|
||||
if (readcnt == -1) {
|
||||
logger->info("Node stopped, exiting");
|
||||
break;
|
||||
}
|
||||
while (!stop) {
|
||||
readcnt = shmem_int_read(&shm, insmps, vectorize);
|
||||
if (readcnt == -1) {
|
||||
logger->info("Node stopped, exiting");
|
||||
break;
|
||||
}
|
||||
|
||||
avail = shmem_int_alloc(&shm, outsmps, readcnt);
|
||||
if (avail < readcnt)
|
||||
logger->warn("Pool underrun: {} / {}", avail, readcnt);
|
||||
avail = shmem_int_alloc(&shm, outsmps, readcnt);
|
||||
if (avail < readcnt)
|
||||
logger->warn("Pool underrun: {} / {}", avail, readcnt);
|
||||
|
||||
for (int i = 0; i < avail; i++) {
|
||||
outsmps[i]->sequence = insmps[i]->sequence;
|
||||
outsmps[i]->ts = insmps[i]->ts;
|
||||
for (int i = 0; i < avail; i++) {
|
||||
outsmps[i]->sequence = insmps[i]->sequence;
|
||||
outsmps[i]->ts = insmps[i]->ts;
|
||||
|
||||
int len = MIN(insmps[i]->length, outsmps[i]->capacity);
|
||||
memcpy(outsmps[i]->data, insmps[i]->data, SAMPLE_DATA_LENGTH(len));
|
||||
int len = MIN(insmps[i]->length, outsmps[i]->capacity);
|
||||
memcpy(outsmps[i]->data, insmps[i]->data, SAMPLE_DATA_LENGTH(len));
|
||||
|
||||
outsmps[i]->length = len;
|
||||
}
|
||||
outsmps[i]->length = len;
|
||||
}
|
||||
|
||||
for (int i = 0; i < readcnt; i++)
|
||||
sample_decref(insmps[i]);
|
||||
for (int i = 0; i < readcnt; i++)
|
||||
sample_decref(insmps[i]);
|
||||
|
||||
writecnt = shmem_int_write(&shm, outsmps, avail);
|
||||
if (writecnt < avail)
|
||||
logger->warn("Short write");
|
||||
writecnt = shmem_int_write(&shm, outsmps, avail);
|
||||
if (writecnt < avail)
|
||||
logger->warn("Short write");
|
||||
|
||||
logger->info("Read / Write: {}/{}", readcnt, writecnt);
|
||||
}
|
||||
logger->info("Read / Write: {}/{}", readcnt, writecnt);
|
||||
}
|
||||
|
||||
ret = shmem_int_close(&shm);
|
||||
if (ret)
|
||||
throw RuntimeError("Failed to close shared-memory interface");
|
||||
ret = shmem_int_close(&shm);
|
||||
if (ret)
|
||||
throw RuntimeError("Failed to close shared-memory interface");
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
villas::node::tools::Shmem t(argc, argv);
|
||||
int main(int argc, char *argv[]) {
|
||||
villas::node::tools::Shmem t(argc, argv);
|
||||
|
||||
return t.run();
|
||||
return t.run();
|
||||
}
|
||||
|
|
|
@ -11,15 +11,15 @@
|
|||
#include <libwebsockets.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/common.hpp>
|
||||
#include <villas/queue_signalled.hpp>
|
||||
#include <villas/exceptions.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/queue_signalled.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -35,41 +35,35 @@ class Request;
|
|||
class Error : public RuntimeError {
|
||||
|
||||
public:
|
||||
template <typename... Args>
|
||||
Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||
const std::string &msg = "Invalid API request", Args &&...args)
|
||||
: RuntimeError(msg, std::forward<Args>(args)...), code(c), json(nullptr) {
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR, const std::string &msg = "Invalid API request", Args&&... args) :
|
||||
RuntimeError(msg, std::forward<Args>(args)...),
|
||||
code(c),
|
||||
json(nullptr)
|
||||
{ }
|
||||
template <typename... Args>
|
||||
Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||
const std::string &msg = "Invalid API request",
|
||||
const char *fmt = nullptr, Args &&...args)
|
||||
: RuntimeError(msg), code(c),
|
||||
json(fmt ? json_pack(fmt, std::forward<Args>(args)...) : nullptr) {}
|
||||
|
||||
template<typename... Args>
|
||||
Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR, const std::string &msg = "Invalid API request", const char *fmt = nullptr, Args&&... args) :
|
||||
RuntimeError(msg),
|
||||
code(c),
|
||||
json(fmt
|
||||
? json_pack(fmt, std::forward<Args>(args)...)
|
||||
: nullptr
|
||||
)
|
||||
{ }
|
||||
|
||||
int code;
|
||||
json_t *json;
|
||||
int code;
|
||||
json_t *json;
|
||||
};
|
||||
|
||||
class BadRequest : public Error {
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
BadRequest(const std::string &msg = "Bad API request", Args&&... args) :
|
||||
Error(HTTP_STATUS_BAD_REQUEST, msg, std::forward<Args>(args)...)
|
||||
{ }
|
||||
template <typename... Args>
|
||||
BadRequest(const std::string &msg = "Bad API request", Args &&...args)
|
||||
: Error(HTTP_STATUS_BAD_REQUEST, msg, std::forward<Args>(args)...) {}
|
||||
};
|
||||
|
||||
class InvalidMethod : public BadRequest {
|
||||
|
||||
public:
|
||||
InvalidMethod(Request *req);
|
||||
InvalidMethod(Request *req);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
@ -80,36 +74,34 @@ class SuperNode;
|
|||
class Api {
|
||||
|
||||
protected:
|
||||
Logger logger;
|
||||
Logger logger;
|
||||
|
||||
enum State state;
|
||||
enum State state;
|
||||
|
||||
std::thread thread;
|
||||
std::atomic<bool> running; // Atomic flag for signalizing thread termination.
|
||||
std::thread thread;
|
||||
std::atomic<bool> running; // Atomic flag for signalizing thread termination.
|
||||
|
||||
SuperNode *super_node;
|
||||
SuperNode *super_node;
|
||||
|
||||
void run();
|
||||
void worker();
|
||||
void run();
|
||||
void worker();
|
||||
|
||||
public:
|
||||
/* Initialize the API.
|
||||
/* Initialize the API.
|
||||
*
|
||||
* Save references to list of paths / nodes for command execution.
|
||||
*/
|
||||
Api(SuperNode *sn);
|
||||
~Api();
|
||||
Api(SuperNode *sn);
|
||||
~Api();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
SuperNode * getSuperNode()
|
||||
{
|
||||
return super_node;
|
||||
}
|
||||
SuperNode *getSuperNode() { return super_node; }
|
||||
|
||||
std::list<api::Session *> sessions; // List of currently active connections
|
||||
villas::QueueSignalled<api::Session *> pending; // A queue of api_sessions which have pending requests.
|
||||
std::list<api::Session *> sessions; // List of currently active connections
|
||||
villas::QueueSignalled<api::Session *>
|
||||
pending; // A queue of api_sessions which have pending requests.
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,17 +7,19 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include <jansson.h>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/api/session.hpp>
|
||||
#include <villas/buffer.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/plugin.hpp>
|
||||
#include <villas/super_node.hpp>
|
||||
#include <villas/api/session.hpp>
|
||||
|
||||
#define RE_UUID "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"
|
||||
#define RE_UUID \
|
||||
"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{" \
|
||||
"12}"
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -30,152 +32,107 @@ class RequestFactory;
|
|||
|
||||
class Request {
|
||||
|
||||
friend Session;
|
||||
friend RequestFactory;
|
||||
friend Response;
|
||||
friend Session;
|
||||
friend RequestFactory;
|
||||
friend Response;
|
||||
|
||||
protected:
|
||||
Session *session;
|
||||
Session *session;
|
||||
|
||||
Logger logger;
|
||||
Buffer buffer;
|
||||
Logger logger;
|
||||
Buffer buffer;
|
||||
|
||||
public:
|
||||
std::vector<std::string> matches;
|
||||
Session::Method method;
|
||||
unsigned long contentLength;
|
||||
json_t *body;
|
||||
std::vector<std::string> matches;
|
||||
Session::Method method;
|
||||
unsigned long contentLength;
|
||||
json_t *body;
|
||||
|
||||
RequestFactory *factory;
|
||||
RequestFactory *factory;
|
||||
|
||||
Request(Session *s) :
|
||||
session(s),
|
||||
method(Session::Method::UNKNOWN),
|
||||
contentLength(0),
|
||||
body(nullptr),
|
||||
factory(nullptr)
|
||||
{ }
|
||||
Request(Session *s)
|
||||
: session(s), method(Session::Method::UNKNOWN), contentLength(0),
|
||||
body(nullptr), factory(nullptr) {}
|
||||
|
||||
virtual
|
||||
~Request()
|
||||
{
|
||||
if (body)
|
||||
json_decref(body);
|
||||
}
|
||||
virtual ~Request() {
|
||||
if (body)
|
||||
json_decref(body);
|
||||
}
|
||||
|
||||
virtual
|
||||
void prepare()
|
||||
{ }
|
||||
virtual void prepare() {}
|
||||
|
||||
virtual
|
||||
Response * execute() = 0;
|
||||
virtual Response *execute() = 0;
|
||||
|
||||
virtual
|
||||
void decode();
|
||||
virtual void decode();
|
||||
|
||||
const std::string & getMatch(int idx) const
|
||||
{
|
||||
return matches[idx];
|
||||
}
|
||||
const std::string &getMatch(int idx) const { return matches[idx]; }
|
||||
|
||||
std::string getQueryArg(const std::string &arg)
|
||||
{
|
||||
char buf[1024];
|
||||
const char *val;
|
||||
std::string getQueryArg(const std::string &arg) {
|
||||
char buf[1024];
|
||||
const char *val;
|
||||
|
||||
val = lws_get_urlarg_by_name(session->wsi, (arg + "=").c_str(), buf, sizeof(buf));
|
||||
val = lws_get_urlarg_by_name(session->wsi, (arg + "=").c_str(), buf,
|
||||
sizeof(buf));
|
||||
|
||||
return val ? std::string(val) : std::string();
|
||||
}
|
||||
return val ? std::string(val) : std::string();
|
||||
}
|
||||
|
||||
std::string getHeader(enum lws_token_indexes hdr)
|
||||
{
|
||||
char buf[1024];
|
||||
std::string getHeader(enum lws_token_indexes hdr) {
|
||||
char buf[1024];
|
||||
|
||||
lws_hdr_copy(session->wsi, buf, sizeof(buf), hdr);
|
||||
lws_hdr_copy(session->wsi, buf, sizeof(buf), hdr);
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
virtual
|
||||
std::string toString();
|
||||
virtual std::string toString();
|
||||
};
|
||||
|
||||
class RequestFactory : public plugin::Plugin {
|
||||
|
||||
public:
|
||||
using plugin::Plugin::Plugin;
|
||||
using plugin::Plugin::Plugin;
|
||||
|
||||
virtual
|
||||
bool match(const std::string &uri, std::smatch &m) const = 0;
|
||||
virtual bool match(const std::string &uri, std::smatch &m) const = 0;
|
||||
|
||||
virtual
|
||||
Request * make(Session *s) = 0;
|
||||
virtual Request *make(Session *s) = 0;
|
||||
|
||||
static
|
||||
Request * create(Session *s, const std::string &uri, Session::Method meth, unsigned long ct);
|
||||
static Request *create(Session *s, const std::string &uri,
|
||||
Session::Method meth, unsigned long ct);
|
||||
|
||||
virtual
|
||||
void init(Request *r)
|
||||
{
|
||||
r->logger = getLogger();
|
||||
}
|
||||
virtual void init(Request *r) { r->logger = getLogger(); }
|
||||
|
||||
virtual
|
||||
std::string
|
||||
getType() const
|
||||
{
|
||||
return "api:request";
|
||||
}
|
||||
virtual std::string getType() const { return "api:request"; }
|
||||
|
||||
virtual
|
||||
bool isHidden() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool isHidden() const { return false; }
|
||||
};
|
||||
|
||||
template<typename T, const char *name, const char *re, const char *desc>
|
||||
template <typename T, const char *name, const char *re, const char *desc>
|
||||
class RequestPlugin : public RequestFactory {
|
||||
|
||||
protected:
|
||||
std::regex regex;
|
||||
std::regex regex;
|
||||
|
||||
public:
|
||||
RequestPlugin() :
|
||||
RequestFactory(),
|
||||
regex(re)
|
||||
{ }
|
||||
RequestPlugin() : RequestFactory(), regex(re) {}
|
||||
|
||||
virtual
|
||||
Request * make(Session *s)
|
||||
{
|
||||
auto *r = new T(s);
|
||||
virtual Request *make(Session *s) {
|
||||
auto *r = new T(s);
|
||||
|
||||
init(r);
|
||||
init(r);
|
||||
|
||||
return r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Get plugin name
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
// Get plugin name
|
||||
virtual std::string getName() const { return name; }
|
||||
|
||||
// Get plugin description
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
// Get plugin description
|
||||
virtual std::string getDescription() const { return desc; }
|
||||
|
||||
virtual
|
||||
bool match(const std::string &uri, std::smatch &match) const
|
||||
{
|
||||
return std::regex_match(uri, match, regex);
|
||||
}
|
||||
virtual bool match(const std::string &uri, std::smatch &match) const {
|
||||
return std::regex_match(uri, match, regex);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -20,13 +20,12 @@ namespace api {
|
|||
class NodeRequest : public Request {
|
||||
|
||||
protected:
|
||||
Node *node;
|
||||
Node *node;
|
||||
|
||||
public:
|
||||
using Request::Request;
|
||||
using Request::Request;
|
||||
|
||||
virtual
|
||||
void prepare();
|
||||
virtual void prepare();
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -18,13 +18,12 @@ namespace api {
|
|||
class PathRequest : public Request {
|
||||
|
||||
protected:
|
||||
class Path *path;
|
||||
class Path *path;
|
||||
|
||||
public:
|
||||
using Request::Request;
|
||||
using Request::Request;
|
||||
|
||||
virtual
|
||||
void prepare();
|
||||
virtual void prepare();
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/nodes/api.hpp>
|
||||
#include <villas/api/requests/node.hpp>
|
||||
#include <villas/nodes/api.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -21,13 +21,12 @@ namespace api {
|
|||
class UniversalRequest : public NodeRequest {
|
||||
|
||||
protected:
|
||||
APINode *api_node;
|
||||
APINode *api_node;
|
||||
|
||||
public:
|
||||
using NodeRequest::NodeRequest;
|
||||
using NodeRequest::NodeRequest;
|
||||
|
||||
virtual
|
||||
void prepare();
|
||||
virtual void prepare();
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
|
||||
#include <jansson.h>
|
||||
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/api.hpp>
|
||||
#include <villas/buffer.hpp>
|
||||
#include <villas/exceptions.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/plugin.hpp>
|
||||
#include <villas/api.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -28,71 +28,60 @@ class Request;
|
|||
class Response {
|
||||
|
||||
public:
|
||||
friend Session;
|
||||
friend Session;
|
||||
|
||||
Response(Session *s, int c = HTTP_STATUS_OK, const std::string &ct = "text/html; charset=UTF-8", const Buffer &b = Buffer());
|
||||
Response(Session *s, int c = HTTP_STATUS_OK,
|
||||
const std::string &ct = "text/html; charset=UTF-8",
|
||||
const Buffer &b = Buffer());
|
||||
|
||||
virtual
|
||||
~Response()
|
||||
{ }
|
||||
virtual ~Response() {}
|
||||
|
||||
virtual
|
||||
void encodeBody()
|
||||
{ }
|
||||
virtual void encodeBody() {}
|
||||
|
||||
int
|
||||
writeBody(struct lws *wsi);
|
||||
int writeBody(struct lws *wsi);
|
||||
|
||||
int
|
||||
writeHeaders(struct lws *wsi);
|
||||
int writeHeaders(struct lws *wsi);
|
||||
|
||||
void
|
||||
setHeader(const std::string &key, const std::string &value)
|
||||
{
|
||||
headers[key] = value;
|
||||
}
|
||||
void setHeader(const std::string &key, const std::string &value) {
|
||||
headers[key] = value;
|
||||
}
|
||||
|
||||
protected:
|
||||
Session *session;
|
||||
Logger logger;
|
||||
Buffer buffer;
|
||||
Session *session;
|
||||
Logger logger;
|
||||
Buffer buffer;
|
||||
|
||||
int code;
|
||||
std::string contentType;
|
||||
std::map<std::string, std::string> headers;
|
||||
int code;
|
||||
std::string contentType;
|
||||
std::map<std::string, std::string> headers;
|
||||
};
|
||||
|
||||
class JsonResponse : public Response {
|
||||
|
||||
protected:
|
||||
json_t *response;
|
||||
json_t *response;
|
||||
|
||||
public:
|
||||
JsonResponse(Session *s, int c, json_t *r) :
|
||||
Response(s, c, "application/json"),
|
||||
response(r)
|
||||
{ }
|
||||
JsonResponse(Session *s, int c, json_t *r)
|
||||
: Response(s, c, "application/json"), response(r) {}
|
||||
|
||||
virtual
|
||||
~JsonResponse();
|
||||
virtual ~JsonResponse();
|
||||
|
||||
virtual
|
||||
void encodeBody();
|
||||
virtual void encodeBody();
|
||||
};
|
||||
|
||||
class ErrorResponse : public JsonResponse {
|
||||
|
||||
public:
|
||||
ErrorResponse(Session *s, const RuntimeError &e) :
|
||||
JsonResponse(s, HTTP_STATUS_INTERNAL_SERVER_ERROR, json_pack("{ s: s }", "error", e.what()))
|
||||
{ }
|
||||
ErrorResponse(Session *s, const RuntimeError &e)
|
||||
: JsonResponse(s, HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||
json_pack("{ s: s }", "error", e.what())) {}
|
||||
|
||||
ErrorResponse(Session *s, const Error &e) :
|
||||
JsonResponse(s, e.code, json_pack("{ s: s }", "error", e.what()))
|
||||
{
|
||||
if (e.json)
|
||||
json_object_update(response, e.json);
|
||||
}
|
||||
ErrorResponse(Session *s, const Error &e)
|
||||
: JsonResponse(s, e.code, json_pack("{ s: s }", "error", e.what())) {
|
||||
if (e.json)
|
||||
json_object_update(response, e.json);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
|
||||
#include <jansson.h>
|
||||
|
||||
#include <villas/queue.h>
|
||||
#include <villas/buffer.hpp>
|
||||
#include <villas/api.hpp>
|
||||
#include <villas/buffer.hpp>
|
||||
#include <villas/queue.h>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -33,72 +33,53 @@ class RequestFactory;
|
|||
class Session {
|
||||
|
||||
public:
|
||||
friend Request; // Requires access to wsi for getting URL args and headers
|
||||
friend StatusRequest; // Requires access to wsi for context status
|
||||
friend RequestFactory;
|
||||
friend Request; // Requires access to wsi for getting URL args and headers
|
||||
friend StatusRequest; // Requires access to wsi for context status
|
||||
friend RequestFactory;
|
||||
|
||||
enum State {
|
||||
ESTABLISHED,
|
||||
SHUTDOWN
|
||||
};
|
||||
enum State { ESTABLISHED, SHUTDOWN };
|
||||
|
||||
enum Version {
|
||||
UNKNOWN_VERSION = 0,
|
||||
VERSION_1 = 1,
|
||||
VERSION_2 = 2
|
||||
};
|
||||
enum Version { UNKNOWN_VERSION = 0, VERSION_1 = 1, VERSION_2 = 2 };
|
||||
|
||||
enum Method {
|
||||
UNKNOWN,
|
||||
GET,
|
||||
POST,
|
||||
DELETE,
|
||||
OPTIONS,
|
||||
PUT,
|
||||
PATCH
|
||||
};
|
||||
enum Method { UNKNOWN, GET, POST, DELETE, OPTIONS, PUT, PATCH };
|
||||
|
||||
protected:
|
||||
enum State state;
|
||||
enum Version version;
|
||||
enum State state;
|
||||
enum Version version;
|
||||
|
||||
lws *wsi;
|
||||
lws *wsi;
|
||||
|
||||
Web *web;
|
||||
Api *api;
|
||||
Web *web;
|
||||
Api *api;
|
||||
|
||||
Logger logger;
|
||||
Logger logger;
|
||||
|
||||
std::unique_ptr<Request> request;
|
||||
std::unique_ptr<Response> response;
|
||||
std::unique_ptr<Request> request;
|
||||
std::unique_ptr<Response> response;
|
||||
|
||||
bool headersSent;
|
||||
bool headersSent;
|
||||
|
||||
public:
|
||||
Session(struct lws *w);
|
||||
~Session();
|
||||
Session(struct lws *w);
|
||||
~Session();
|
||||
|
||||
std::string getName() const;
|
||||
std::string getName() const;
|
||||
|
||||
SuperNode * getSuperNode() const
|
||||
{
|
||||
return api->getSuperNode();
|
||||
}
|
||||
SuperNode *getSuperNode() const { return api->getSuperNode(); }
|
||||
|
||||
void open(void *in, size_t len);
|
||||
int writeable();
|
||||
void body(void *in, size_t len);
|
||||
void bodyComplete();
|
||||
void execute();
|
||||
void shutdown();
|
||||
void open(void *in, size_t len);
|
||||
int writeable();
|
||||
void body(void *in, size_t len);
|
||||
void bodyComplete();
|
||||
void execute();
|
||||
void shutdown();
|
||||
|
||||
static
|
||||
int protocolCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
||||
static int protocolCallback(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
|
||||
Method getRequestMethod() const;
|
||||
Method getRequestMethod() const;
|
||||
|
||||
static
|
||||
std::string methodToString(Method meth);
|
||||
static std::string methodToString(Method meth);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
@ -21,33 +21,30 @@ namespace node {
|
|||
namespace api {
|
||||
namespace universal {
|
||||
|
||||
enum PayloadType {
|
||||
SAMPLES = 0,
|
||||
EVENTS = 1
|
||||
};
|
||||
enum PayloadType { SAMPLES = 0, EVENTS = 1 };
|
||||
|
||||
// Channel (uAPI) is a synonym for signal (VILLAS)
|
||||
class Channel {
|
||||
public:
|
||||
std::string description;
|
||||
PayloadType payload;
|
||||
double range_min;
|
||||
double range_max;
|
||||
std::vector<std::string> range_options;
|
||||
double rate;
|
||||
bool readable;
|
||||
bool writable;
|
||||
std::string description;
|
||||
PayloadType payload;
|
||||
double range_min;
|
||||
double range_max;
|
||||
std::vector<std::string> range_options;
|
||||
double rate;
|
||||
bool readable;
|
||||
bool writable;
|
||||
|
||||
using Ptr = std::shared_ptr<Channel>;
|
||||
using Ptr = std::shared_ptr<Channel>;
|
||||
|
||||
void parse(json_t *json);
|
||||
json_t * toJson(Signal::Ptr sig) const;
|
||||
void parse(json_t *json);
|
||||
json_t *toJson(Signal::Ptr sig) const;
|
||||
};
|
||||
|
||||
class ChannelList : public std::vector<Channel::Ptr> {
|
||||
|
||||
public:
|
||||
void parse(json_t *json, bool readable, bool writable);
|
||||
void parse(json_t *json, bool readable, bool writable);
|
||||
};
|
||||
|
||||
} // namespace universal
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
namespace villas {
|
||||
namespace node {
|
||||
|
||||
json_t * getCapabilities();
|
||||
json_t *getCapabilities();
|
||||
|
||||
} // namespace node
|
||||
} // namepace vilals
|
||||
} // namespace villas
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
#include <jansson.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <functional>
|
||||
#include <regex>
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
|
||||
#ifdef WITH_CONFIG
|
||||
#include <libconfig.h>
|
||||
#include <libconfig.h>
|
||||
#endif
|
||||
|
||||
namespace villas {
|
||||
|
@ -27,65 +27,66 @@ namespace node {
|
|||
class Config {
|
||||
|
||||
protected:
|
||||
using str_walk_fcn_t = std::function<json_t *(json_t *)>;
|
||||
using str_walk_fcn_t = std::function<json_t *(json_t *)>;
|
||||
|
||||
Logger logger;
|
||||
Logger logger;
|
||||
|
||||
std::list<std::string> includeDirectories;
|
||||
std::list<std::string> includeDirectories;
|
||||
|
||||
// Check if file exists on local system.
|
||||
static
|
||||
bool isLocalFile(const std::string &uri)
|
||||
{
|
||||
return access(uri.c_str(), F_OK) != -1;
|
||||
}
|
||||
// Check if file exists on local system.
|
||||
static bool isLocalFile(const std::string &uri) {
|
||||
return access(uri.c_str(), F_OK) != -1;
|
||||
}
|
||||
|
||||
// Decode configuration file.
|
||||
json_t * decode(FILE *f);
|
||||
// Decode configuration file.
|
||||
json_t *decode(FILE *f);
|
||||
|
||||
#ifdef WITH_CONFIG
|
||||
// Convert libconfig .conf file to libjansson .json file.
|
||||
json_t * libconfigDecode(FILE *f);
|
||||
// Convert libconfig .conf file to libjansson .json file.
|
||||
json_t *libconfigDecode(FILE *f);
|
||||
|
||||
static
|
||||
const char ** includeFuncStub(config_t *cfg, const char *include_dir, const char *path, const char **error);
|
||||
static const char **includeFuncStub(config_t *cfg, const char *include_dir,
|
||||
const char *path, const char **error);
|
||||
|
||||
const char ** includeFunc(config_t *cfg, const char *include_dir, const char *path, const char **error);
|
||||
const char **includeFunc(config_t *cfg, const char *include_dir,
|
||||
const char *path, const char **error);
|
||||
#endif // WITH_CONFIG
|
||||
|
||||
// Load configuration from standard input (stdim).
|
||||
FILE * loadFromStdio();
|
||||
// Load configuration from standard input (stdim).
|
||||
FILE *loadFromStdio();
|
||||
|
||||
// Load configuration from local file.
|
||||
FILE * loadFromLocalFile(const std::string &u);
|
||||
// Load configuration from local file.
|
||||
FILE *loadFromLocalFile(const std::string &u);
|
||||
|
||||
std::list<std::string> resolveIncludes(const std::string &name);
|
||||
std::list<std::string> resolveIncludes(const std::string &name);
|
||||
|
||||
void resolveEnvVars(std::string &text);
|
||||
void resolveEnvVars(std::string &text);
|
||||
|
||||
// Resolve custom include directives.
|
||||
json_t * expandIncludes(json_t *in);
|
||||
// Resolve custom include directives.
|
||||
json_t *expandIncludes(json_t *in);
|
||||
|
||||
// To shell-like subsitution of environment variables in strings.
|
||||
json_t * expandEnvVars(json_t *in);
|
||||
// To shell-like subsitution of environment variables in strings.
|
||||
json_t *expandEnvVars(json_t *in);
|
||||
|
||||
// Run a callback function for each string in the config
|
||||
json_t * walkStrings(json_t *in, str_walk_fcn_t cb);
|
||||
// Run a callback function for each string in the config
|
||||
json_t *walkStrings(json_t *in, str_walk_fcn_t cb);
|
||||
|
||||
// Get the include dirs
|
||||
std::list<std::string> getIncludeDirectories(FILE *f) const;
|
||||
// Get the include dirs
|
||||
std::list<std::string> getIncludeDirectories(FILE *f) const;
|
||||
|
||||
public:
|
||||
json_t *root;
|
||||
json_t *root;
|
||||
|
||||
Config();
|
||||
Config(const std::string &u);
|
||||
Config();
|
||||
Config(const std::string &u);
|
||||
|
||||
~Config();
|
||||
~Config();
|
||||
|
||||
json_t * load(std::FILE *f, bool resolveIncludes = true, bool resolveEnvVars = true);
|
||||
json_t *load(std::FILE *f, bool resolveIncludes = true,
|
||||
bool resolveEnvVars = true);
|
||||
|
||||
json_t * load(const std::string &u, bool resolveIncludes = true, bool resolveEnvVars = true);
|
||||
json_t *load(const std::string &u, bool resolveIncludes = true,
|
||||
bool resolveEnvVars = true);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef WITH_CONFIG
|
||||
#include <libconfig.h>
|
||||
#include <libconfig.h>
|
||||
#endif
|
||||
|
||||
#include <jansson.h>
|
||||
|
@ -22,7 +22,7 @@ namespace node {
|
|||
#ifdef WITH_CONFIG
|
||||
|
||||
// Convert a libconfig object to a jansson object
|
||||
json_t * config_to_json(struct config_setting_t *cfg);
|
||||
json_t *config_to_json(struct config_setting_t *cfg);
|
||||
|
||||
// Convert a jansson object into a libconfig object.
|
||||
int json_to_config(json_t *json, struct config_setting_t *parent);
|
||||
|
@ -31,14 +31,16 @@ int json_to_config(json_t *json, struct config_setting_t *parent);
|
|||
|
||||
int json_object_extend_str(json_t *orig, const char *str);
|
||||
|
||||
void json_object_extend_key_value(json_t *obj, const char *key, const char *value);
|
||||
void json_object_extend_key_value(json_t *obj, const char *key,
|
||||
const char *value);
|
||||
|
||||
void json_object_extend_key_value_token(json_t *obj, const char *key, const char *value);
|
||||
void json_object_extend_key_value_token(json_t *obj, const char *key,
|
||||
const char *value);
|
||||
|
||||
// Merge two JSON objects recursively.
|
||||
int json_object_extend(json_t *orig, json_t *merge);
|
||||
|
||||
json_t * json_load_cli(int argc, const char *argv[]);
|
||||
json_t *json_load_cli(int argc, const char *argv[]);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -17,25 +17,25 @@ namespace node {
|
|||
class Dumper {
|
||||
|
||||
protected:
|
||||
bool active;
|
||||
int socketFd;
|
||||
std::string socketPath;
|
||||
bool supressRepeatedWarning;
|
||||
uint64_t warningCounter;
|
||||
Logger logger;
|
||||
bool active;
|
||||
int socketFd;
|
||||
std::string socketPath;
|
||||
bool supressRepeatedWarning;
|
||||
uint64_t warningCounter;
|
||||
Logger logger;
|
||||
|
||||
public:
|
||||
Dumper();
|
||||
~Dumper();
|
||||
Dumper();
|
||||
~Dumper();
|
||||
|
||||
int openSocket();
|
||||
int closeSocket();
|
||||
bool isActive();
|
||||
int setActive();
|
||||
int openSocket();
|
||||
int closeSocket();
|
||||
bool isActive();
|
||||
int setActive();
|
||||
|
||||
int setPath(const std::string &socketPathIn);
|
||||
void writeDataCSV(unsigned len, double *yData, double *xData = nullptr);
|
||||
void writeDataBinary(unsigned len, double *yData, double *xData = nullptr);
|
||||
int setPath(const std::string &socketPathIn);
|
||||
void writeDataCSV(unsigned len, double *yData, double *xData = nullptr);
|
||||
void writeDataBinary(unsigned len, double *yData, double *xData = nullptr);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -22,58 +22,46 @@ class FormatFactory;
|
|||
|
||||
class Format {
|
||||
|
||||
friend FormatFactory;
|
||||
friend FormatFactory;
|
||||
|
||||
public:
|
||||
using Ptr = std::unique_ptr<Format>;
|
||||
using Ptr = std::unique_ptr<Format>;
|
||||
|
||||
protected:
|
||||
int flags; // A set of flags which is automatically used.
|
||||
int real_precision; // Number of digits used for floatint point numbers
|
||||
|
||||
int flags; // A set of flags which is automatically used.
|
||||
int real_precision; // Number of digits used for floatint point numbers
|
||||
Logger logger;
|
||||
|
||||
Logger logger;
|
||||
struct {
|
||||
char *buffer;
|
||||
size_t buflen;
|
||||
} in, out;
|
||||
|
||||
struct {
|
||||
char *buffer;
|
||||
size_t buflen;
|
||||
} in, out;
|
||||
|
||||
SignalList::Ptr signals; // Signal meta data for parsed samples by Format::scan()
|
||||
SignalList::Ptr
|
||||
signals; // Signal meta data for parsed samples by Format::scan()
|
||||
|
||||
public:
|
||||
Format(int fl);
|
||||
Format(int fl);
|
||||
|
||||
virtual
|
||||
~Format();
|
||||
virtual ~Format();
|
||||
|
||||
const SignalList::Ptr getSignals() const
|
||||
{
|
||||
return signals;
|
||||
}
|
||||
const SignalList::Ptr getSignals() const { return signals; }
|
||||
|
||||
int getFlags() const
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
int getFlags() const { return flags; }
|
||||
|
||||
void start(const SignalList::Ptr sigs, int fl = (int) SampleFlags::HAS_ALL);
|
||||
void start(const std::string &dtypes, int fl = (int) SampleFlags::HAS_ALL);
|
||||
void start(const SignalList::Ptr sigs, int fl = (int)SampleFlags::HAS_ALL);
|
||||
void start(const std::string &dtypes, int fl = (int)SampleFlags::HAS_ALL);
|
||||
|
||||
virtual
|
||||
void start()
|
||||
{ }
|
||||
virtual void start() {}
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
|
||||
virtual
|
||||
int print(FILE *f, const struct Sample * const smps[], unsigned cnt);
|
||||
virtual int print(FILE *f, const struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int scan(FILE *f, 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.
|
||||
/* 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.
|
||||
|
@ -84,10 +72,10 @@ public:
|
|||
* @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;
|
||||
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.
|
||||
/* 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.
|
||||
|
@ -98,98 +86,65 @@ public:
|
|||
* @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;
|
||||
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
|
||||
// Wrappers for sending a (un)parsing single samples
|
||||
|
||||
int print(FILE *f, const struct Sample *smp)
|
||||
{
|
||||
return print(f, &smp, 1);
|
||||
}
|
||||
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 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 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);
|
||||
}
|
||||
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;
|
||||
using Format::Format;
|
||||
};
|
||||
|
||||
class FormatFactory : public plugin::Plugin {
|
||||
|
||||
public:
|
||||
using plugin::Plugin::Plugin;
|
||||
using plugin::Plugin::Plugin;
|
||||
|
||||
virtual
|
||||
Format * make() = 0;
|
||||
virtual Format *make() = 0;
|
||||
|
||||
static
|
||||
Format * make(json_t *json);
|
||||
static Format *make(json_t *json);
|
||||
|
||||
static
|
||||
Format * make(const std::string &format);
|
||||
static Format *make(const std::string &format);
|
||||
|
||||
virtual
|
||||
void init(Format *f)
|
||||
{
|
||||
f->logger = getLogger();
|
||||
}
|
||||
virtual void init(Format *f) { f->logger = getLogger(); }
|
||||
|
||||
virtual
|
||||
std::string getType() const
|
||||
{
|
||||
return "format";
|
||||
}
|
||||
virtual std::string getType() const { return "format"; }
|
||||
|
||||
virtual
|
||||
bool isHidden() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool isHidden() const { return false; }
|
||||
};
|
||||
|
||||
template <typename T, const char *name, const char *desc, int flags = 0>
|
||||
class FormatPlugin : public FormatFactory {
|
||||
|
||||
public:
|
||||
using FormatFactory::FormatFactory;
|
||||
using FormatFactory::FormatFactory;
|
||||
|
||||
virtual
|
||||
Format * make()
|
||||
{
|
||||
auto *f = new T(flags);
|
||||
virtual Format *make() {
|
||||
auto *f = new T(flags);
|
||||
|
||||
init(f);
|
||||
init(f);
|
||||
|
||||
return f;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
virtual std::string getName() const { return name; }
|
||||
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
virtual std::string getDescription() const { return desc; }
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -20,51 +20,36 @@ struct Sample;
|
|||
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);
|
||||
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
|
||||
char separator; // Column separator
|
||||
|
||||
public:
|
||||
ColumnLineFormat(int fl, char delim, char sep) :
|
||||
LineFormat(fl, delim),
|
||||
separator(sep)
|
||||
{ }
|
||||
ColumnLineFormat(int fl, char delim, char sep)
|
||||
: LineFormat(fl, delim), separator(sep) {}
|
||||
|
||||
virtual
|
||||
void header(FILE *f, const SignalList::Ptr sigs);
|
||||
virtual void header(FILE *f, const SignalList::Ptr sigs);
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
};
|
||||
|
||||
template <const char *name, const char *desc, int flags = 0, char delimiter = '\n', char separator = '\t'>
|
||||
template <const char *name, const char *desc, int flags = 0,
|
||||
char delimiter = '\n', char separator = '\t'>
|
||||
class ColumnLineFormatPlugin : public FormatFactory {
|
||||
|
||||
public:
|
||||
using FormatFactory::FormatFactory;
|
||||
using FormatFactory::FormatFactory;
|
||||
|
||||
virtual
|
||||
Format * make()
|
||||
{
|
||||
return new ColumnLineFormat(flags, delimiter, separator);
|
||||
}
|
||||
virtual Format *make() {
|
||||
return new ColumnLineFormat(flags, delimiter, separator);
|
||||
}
|
||||
|
||||
/// Get plugin name
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
/// Get plugin name
|
||||
virtual std::string getName() const { return name; }
|
||||
|
||||
/// Get plugin description
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
/// Get plugin description
|
||||
virtual std::string getDescription() const { return desc; }
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -18,14 +18,14 @@ struct Sample;
|
|||
class IotAgentUltraLightFormat : public Format {
|
||||
|
||||
protected:
|
||||
virtual
|
||||
int sprint(char *buf, size_t len, size_t *wbytes, const 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
|
||||
int sscan(const char *buf, size_t len, size_t *rbytes, struct Sample * const smps[], unsigned cnt);
|
||||
virtual int sscan(const char *buf, size_t len, size_t *rbytes,
|
||||
struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
using Format::Format;
|
||||
using Format::Format;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -20,41 +20,32 @@ struct Sample;
|
|||
class JsonFormat : public Format {
|
||||
|
||||
protected:
|
||||
static
|
||||
enum SignalType detect(const json_t *val);
|
||||
static enum SignalType detect(const json_t *val);
|
||||
|
||||
json_t * packTimestamps(const struct Sample *smp);
|
||||
int unpackTimestamps(json_t *json_ts, struct Sample *smp);
|
||||
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);
|
||||
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;
|
||||
int dump_flags;
|
||||
|
||||
public:
|
||||
JsonFormat(int fl) :
|
||||
Format(fl),
|
||||
dump_flags(0)
|
||||
{ }
|
||||
JsonFormat(int fl) : Format(fl), dump_flags(0) {}
|
||||
|
||||
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 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
|
||||
int print(FILE *f, const 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 int scan(FILE *f, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -15,13 +15,11 @@ namespace node {
|
|||
class JsonEdgeflexFormat : public JsonFormat {
|
||||
|
||||
protected:
|
||||
virtual
|
||||
int packSample(json_t **j, const struct Sample *smp);
|
||||
virtual
|
||||
int unpackSample(json_t *json_smp, struct Sample *smp);
|
||||
virtual int packSample(json_t **j, const struct Sample *smp);
|
||||
virtual int unpackSample(json_t *json_smp, struct Sample *smp);
|
||||
|
||||
public:
|
||||
using JsonFormat::JsonFormat;
|
||||
using JsonFormat::JsonFormat;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/signal_type.hpp>
|
||||
#include <villas/formats/json.hpp>
|
||||
#include <villas/signal_type.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -16,20 +16,17 @@ namespace node {
|
|||
class JsonKafkaFormat : public JsonFormat {
|
||||
|
||||
protected:
|
||||
virtual
|
||||
int packSample(json_t **j, const struct Sample *smp);
|
||||
virtual
|
||||
int unpackSample(json_t *json_smp, struct Sample *smp);
|
||||
virtual int packSample(json_t **j, const struct Sample *smp);
|
||||
virtual int unpackSample(json_t *json_smp, struct Sample *smp);
|
||||
|
||||
const char * villasToKafkaType(enum SignalType vt);
|
||||
const char *villasToKafkaType(enum SignalType vt);
|
||||
|
||||
json_t *json_schema;
|
||||
json_t *json_schema;
|
||||
|
||||
public:
|
||||
JsonKafkaFormat(int fl);
|
||||
JsonKafkaFormat(int fl);
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -15,13 +15,11 @@ namespace node {
|
|||
class JsonReserveFormat : public JsonFormat {
|
||||
|
||||
protected:
|
||||
virtual
|
||||
int packSample(json_t **j, const struct Sample *smp);
|
||||
virtual
|
||||
int unpackSample(json_t *json_smp, struct Sample *smp);
|
||||
virtual int packSample(json_t **j, const struct Sample *smp);
|
||||
virtual int unpackSample(json_t *json_smp, struct Sample *smp);
|
||||
|
||||
public:
|
||||
using JsonFormat::JsonFormat;
|
||||
using JsonFormat::JsonFormat;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -15,77 +15,54 @@ 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;
|
||||
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.
|
||||
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 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;
|
||||
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)
|
||||
{ }
|
||||
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 SignalList::Ptr sigs)
|
||||
{
|
||||
header_printed = true;
|
||||
}
|
||||
// Print a header
|
||||
virtual void header(FILE *f, const SignalList::Ptr 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 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 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);
|
||||
virtual void parse(json_t *json);
|
||||
};
|
||||
|
||||
template <typename T, const char *name, const char *desc, int flags = 0, char delimiter = '\n'>
|
||||
template <typename T, const char *name, const char *desc, int flags = 0,
|
||||
char delimiter = '\n'>
|
||||
class LineFormatPlugin : public FormatFactory {
|
||||
|
||||
public:
|
||||
using FormatFactory::FormatFactory;
|
||||
using FormatFactory::FormatFactory;
|
||||
|
||||
virtual
|
||||
Format * make()
|
||||
{
|
||||
return new T(flags, delimiter);
|
||||
}
|
||||
virtual Format *make() { return new T(flags, delimiter); }
|
||||
|
||||
/// Get plugin name
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
/// Get plugin name
|
||||
virtual std::string getName() const { return name; }
|
||||
|
||||
/// Get plugin description
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
/// Get plugin description
|
||||
virtual std::string getDescription() const { return desc; }
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include<villas/signal_list.hpp>
|
||||
#include <villas/signal_list.hpp>
|
||||
|
||||
namespace villas {
|
||||
|
||||
|
@ -43,10 +43,12 @@ void msg_hdr_ntoh(struct Message *m);
|
|||
int msg_verify(const struct Message *m);
|
||||
|
||||
// Copy fields from \p msg into \p smp.
|
||||
int msg_to_sample(const struct Message *msg, struct Sample *smp, const SignalList::Ptr sigs, uint8_t *source_index);
|
||||
int msg_to_sample(const struct Message *msg, struct Sample *smp,
|
||||
const SignalList::Ptr sigs, uint8_t *source_index);
|
||||
|
||||
// Copy fields form \p smp into \p msg.
|
||||
int msg_from_sample(struct Message *msg, const struct Sample *smp, const SignalList::Ptr sigs, uint8_t source_index);
|
||||
int msg_from_sample(struct Message *msg, const struct Sample *smp,
|
||||
const SignalList::Ptr sigs, uint8_t source_index);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -10,60 +10,62 @@
|
|||
#include <cstdint>
|
||||
|
||||
// The current version number for the message format
|
||||
#define MSG_VERSION 2
|
||||
#define MSG_VERSION 2
|
||||
|
||||
// TODO: Implement more message types
|
||||
#define MSG_TYPE_DATA 0 // Message contains float / integer values
|
||||
#define MSG_TYPE_START 1 // Message marks the beginning of a new simulation case
|
||||
#define MSG_TYPE_STOP 2 // Message marks the end of a simulation case
|
||||
#define MSG_TYPE_DATA 0 // Message contains float / integer values
|
||||
#define MSG_TYPE_START 1 // Message marks the beginning of a new simulation case
|
||||
#define MSG_TYPE_STOP 2 // Message marks the end of a simulation case
|
||||
|
||||
// The total size in bytes of a message
|
||||
#define MSG_LEN(values) (sizeof(struct Message) + MSG_DATA_LEN(values))
|
||||
#define MSG_LEN(values) (sizeof(struct Message) + MSG_DATA_LEN(values))
|
||||
|
||||
// The length of \p values values in bytes.
|
||||
#define MSG_DATA_LEN(values) (sizeof(float) * (values))
|
||||
#define MSG_DATA_LEN(values) (sizeof(float) * (values))
|
||||
|
||||
// The offset to the first data value in a message.
|
||||
#define MSG_DATA_OFFSET(msg) ((char *) (msg) + offsetof(struct Message, data))
|
||||
#define MSG_DATA_OFFSET(msg) ((char *)(msg) + offsetof(struct Message, data))
|
||||
|
||||
// The timestamp of a message in struct timespec format
|
||||
#define MSG_TS(msg, i) \
|
||||
i.tv_sec = (msg)->ts.sec; \
|
||||
i.tv_nsec = (msg)->ts.nsec;
|
||||
#define MSG_TS(msg, i) \
|
||||
i.tv_sec = (msg)->ts.sec; \
|
||||
i.tv_nsec = (msg)->ts.nsec;
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
||||
// This message format is used by all clients
|
||||
struct Message
|
||||
{
|
||||
struct Message {
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
unsigned version: 4; // Specifies the format of the remaining message (see MGS_VERSION)
|
||||
unsigned type : 2; // Data or control message (see MSG_TYPE_*)
|
||||
unsigned reserved1 : 2; // Reserved bits
|
||||
unsigned
|
||||
version : 4; // Specifies the format of the remaining message (see MGS_VERSION)
|
||||
unsigned type : 2; // Data or control message (see MSG_TYPE_*)
|
||||
unsigned reserved1 : 2; // Reserved bits
|
||||
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||
unsigned reserved1 : 2; // Reserved bits
|
||||
unsigned type : 2; // Data or control message (see MSG_TYPE_*)
|
||||
unsigned version: 4; // Specifies the format of the remaining message (see MGS_VERSION)
|
||||
unsigned reserved1 : 2; // Reserved bits
|
||||
unsigned type : 2; // Data or control message (see MSG_TYPE_*)
|
||||
unsigned
|
||||
version : 4; // Specifies the format of the remaining message (see MGS_VERSION)
|
||||
#else
|
||||
#error Invalid byte-order
|
||||
#error Invalid byte-order
|
||||
#endif
|
||||
|
||||
uint8_t source_index; // An id which identifies the source of this sample.
|
||||
uint16_t length; // The number of values in msg::data[].
|
||||
uint32_t sequence; // The sequence number is incremented by one for consecutive messages.
|
||||
uint8_t source_index; // An id which identifies the source of this sample.
|
||||
uint16_t length; // The number of values in msg::data[].
|
||||
uint32_t
|
||||
sequence; // The sequence number is incremented by one for consecutive messages.
|
||||
|
||||
// A timestamp per message.
|
||||
struct {
|
||||
uint32_t sec; // Seconds since 1970-01-01 00:00:00
|
||||
uint32_t nsec; // Nanoseconds of the current second
|
||||
} ts;
|
||||
// A timestamp per message.
|
||||
struct {
|
||||
uint32_t sec; // Seconds since 1970-01-01 00:00:00
|
||||
uint32_t nsec; // Nanoseconds of the current second
|
||||
} ts;
|
||||
|
||||
// The message payload.
|
||||
union {
|
||||
float f; // Floating point values
|
||||
uint32_t i; // Integer values
|
||||
} data[];
|
||||
// The message payload.
|
||||
union {
|
||||
float f; // Floating point values
|
||||
uint32_t i; // Integer values
|
||||
} data[];
|
||||
} __attribute__((packed));
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -20,56 +20,45 @@ struct Sample;
|
|||
class OpalAsyncIPFormat : public BinaryFormat {
|
||||
|
||||
protected:
|
||||
const unsigned MAXSIZE = 64;
|
||||
const unsigned 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));
|
||||
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;
|
||||
int16_t dev_id;
|
||||
|
||||
public:
|
||||
OpalAsyncIPFormat(int fl, uint8_t did = 0) :
|
||||
BinaryFormat(fl),
|
||||
dev_id(did)
|
||||
{ }
|
||||
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 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);
|
||||
virtual void parse(json_t *json);
|
||||
};
|
||||
|
||||
class OpalAsyncIPFormatPlugin : public FormatFactory {
|
||||
|
||||
public:
|
||||
using FormatFactory::FormatFactory;
|
||||
using FormatFactory::FormatFactory;
|
||||
|
||||
virtual
|
||||
Format * make()
|
||||
{
|
||||
return new OpalAsyncIPFormat((int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA);
|
||||
}
|
||||
virtual Format *make() {
|
||||
return new OpalAsyncIPFormat((int)SampleFlags::HAS_SEQUENCE |
|
||||
(int)SampleFlags::HAS_DATA);
|
||||
}
|
||||
|
||||
/// Get plugin name
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return "opal.asyncip";
|
||||
}
|
||||
/// 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";
|
||||
}
|
||||
/// Get plugin description
|
||||
virtual std::string getDescription() const {
|
||||
return "OPAL-RTs AsyncIP example format";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -23,15 +23,15 @@ struct Sample;
|
|||
class ProtobufFormat : public BinaryFormat {
|
||||
|
||||
protected:
|
||||
enum SignalType detect(const Villas__Node__Value *val);
|
||||
enum SignalType detect(const Villas__Node__Value *val);
|
||||
|
||||
public:
|
||||
using BinaryFormat::BinaryFormat;
|
||||
using BinaryFormat::BinaryFormat;
|
||||
|
||||
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 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);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
#include <villas/format.hpp>
|
||||
|
||||
// float128 is currently not yet supported as htole128() functions a missing
|
||||
#if 0 && defined(__GNUC__) && defined(__linux__)
|
||||
#define HAS_128BIT
|
||||
#define HAS_128BIT
|
||||
#endif
|
||||
|
||||
namespace villas {
|
||||
|
@ -26,43 +26,32 @@ struct Sample;
|
|||
class RawFormat : public BinaryFormat {
|
||||
|
||||
public:
|
||||
enum Endianess {
|
||||
BIG,
|
||||
LITTLE
|
||||
};
|
||||
enum Endianess { BIG, LITTLE };
|
||||
|
||||
protected:
|
||||
|
||||
enum Endianess endianess;
|
||||
int bits;
|
||||
bool fake;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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 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);
|
||||
virtual void parse(json_t *json);
|
||||
};
|
||||
|
||||
class GtnetRawFormat : public RawFormat {
|
||||
|
||||
public:
|
||||
GtnetRawFormat(int fl) :
|
||||
RawFormat(fl, 32, Endianess::BIG)
|
||||
{ }
|
||||
GtnetRawFormat(int fl) : RawFormat(fl, 32, Endianess::BIG) {}
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -17,12 +17,12 @@ namespace node {
|
|||
class ValueFormat : public Format {
|
||||
|
||||
public:
|
||||
using Format::Format;
|
||||
using Format::Format;
|
||||
|
||||
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 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);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -20,63 +20,56 @@ struct Sample;
|
|||
class VillasBinaryFormat : public BinaryFormat {
|
||||
|
||||
protected:
|
||||
uint8_t source_index;
|
||||
bool web;
|
||||
bool validate_source_index;
|
||||
uint8_t source_index;
|
||||
bool web;
|
||||
bool validate_source_index;
|
||||
|
||||
public:
|
||||
VillasBinaryFormat(int fl, bool w, uint8_t sid = 0) :
|
||||
BinaryFormat(fl),
|
||||
source_index(sid),
|
||||
web(w),
|
||||
validate_source_index(false)
|
||||
{ }
|
||||
VillasBinaryFormat(int fl, bool w, uint8_t sid = 0)
|
||||
: BinaryFormat(fl), source_index(sid), web(w),
|
||||
validate_source_index(false) {}
|
||||
|
||||
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 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);
|
||||
virtual void parse(json_t *json);
|
||||
};
|
||||
|
||||
template<bool web = false>
|
||||
template <bool web = false>
|
||||
class VillasBinaryFormatPlugin : public FormatFactory {
|
||||
|
||||
public:
|
||||
using FormatFactory::FormatFactory;
|
||||
using FormatFactory::FormatFactory;
|
||||
|
||||
virtual
|
||||
Format * make()
|
||||
{
|
||||
return new VillasBinaryFormat((int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA, web);
|
||||
}
|
||||
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;
|
||||
/// Get plugin name
|
||||
virtual std::string getName() const {
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "villas." << (web ? "web" : "binary");
|
||||
ss << "villas." << (web ? "web" : "binary");
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// Get plugin description
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
/// Get plugin description
|
||||
virtual std::string getDescription() const {
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "VILLAS binary network format";
|
||||
ss << "VILLAS binary network format";
|
||||
|
||||
if (web)
|
||||
ss << " for WebSockets";
|
||||
if (web)
|
||||
ss << " for WebSockets";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -17,16 +17,13 @@ namespace node {
|
|||
class VILLASHumanFormat : 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);
|
||||
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);
|
||||
|
||||
public:
|
||||
using LineFormat::LineFormat;
|
||||
using LineFormat::LineFormat;
|
||||
|
||||
virtual
|
||||
void header(FILE *f, const SignalList::Ptr sigs);
|
||||
virtual void header(FILE *f, const SignalList::Ptr sigs);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/exceptions.hpp>
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/signal.hpp>
|
||||
#include <villas/signal_list.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/plugin.hpp>
|
||||
#include <villas/exceptions.hpp>
|
||||
#include <villas/signal.hpp>
|
||||
#include <villas/signal_list.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -29,285 +29,195 @@ class HookFactory;
|
|||
|
||||
class Hook {
|
||||
|
||||
friend HookFactory;
|
||||
friend HookFactory;
|
||||
|
||||
public:
|
||||
using Ptr = std::shared_ptr<Hook>;
|
||||
using Ptr = std::shared_ptr<Hook>;
|
||||
|
||||
enum class Flags {
|
||||
BUILTIN = (1 << 0), // Should we add this hook by default to every path?.
|
||||
PATH = (1 << 1), // This hook type is used by paths.
|
||||
NODE_READ = (1 << 2), // This hook type is used by nodes.
|
||||
NODE_WRITE = (1 << 3) // This hook type is used by nodes.
|
||||
};
|
||||
enum class Flags {
|
||||
BUILTIN = (1 << 0), // Should we add this hook by default to every path?.
|
||||
PATH = (1 << 1), // This hook type is used by paths.
|
||||
NODE_READ = (1 << 2), // This hook type is used by nodes.
|
||||
NODE_WRITE = (1 << 3) // This hook type is used by nodes.
|
||||
};
|
||||
|
||||
enum class Reason {
|
||||
OK = 0,
|
||||
ERROR,
|
||||
SKIP_SAMPLE,
|
||||
STOP_PROCESSING
|
||||
};
|
||||
enum class Reason { OK = 0, ERROR, SKIP_SAMPLE, STOP_PROCESSING };
|
||||
|
||||
protected:
|
||||
Logger logger;
|
||||
Logger logger;
|
||||
|
||||
HookFactory *factory;
|
||||
HookFactory *factory;
|
||||
|
||||
enum State state;
|
||||
enum State state;
|
||||
|
||||
int flags;
|
||||
unsigned priority; // A priority to change the order of execution within one type of hook.
|
||||
bool enabled; // Is this hook active?
|
||||
int flags;
|
||||
unsigned
|
||||
priority; // A priority to change the order of execution within one type of hook.
|
||||
bool enabled; // Is this hook active?
|
||||
|
||||
Path *path;
|
||||
Node *node;
|
||||
Path *path;
|
||||
Node *node;
|
||||
|
||||
SignalList::Ptr signals;
|
||||
SignalList::Ptr signals;
|
||||
|
||||
json_t *config; // A JSON object containing the configuration of the hook.
|
||||
json_t *config; // A JSON object containing the configuration of the hook.
|
||||
|
||||
public:
|
||||
Hook(Path *p, Node *n, int fl, int prio, bool en = true);
|
||||
Hook(Path *p, Node *n, int fl, int prio, bool en = true);
|
||||
|
||||
virtual
|
||||
~Hook()
|
||||
{ }
|
||||
virtual ~Hook() {}
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
|
||||
void prepare(SignalList::Ptr sigs);
|
||||
void prepare(SignalList::Ptr sigs);
|
||||
|
||||
Logger getLogger()
|
||||
{
|
||||
return logger;
|
||||
}
|
||||
Logger getLogger() { return logger; }
|
||||
|
||||
// Called whenever a hook is started; before threads are created.
|
||||
virtual
|
||||
void start()
|
||||
{
|
||||
assert(state == State::PREPARED);
|
||||
// Called whenever a hook is started; before threads are created.
|
||||
virtual void start() {
|
||||
assert(state == State::PREPARED);
|
||||
|
||||
state = State::STARTED;
|
||||
}
|
||||
state = State::STARTED;
|
||||
}
|
||||
|
||||
// Called whenever a hook is stopped; after threads are destoyed.
|
||||
virtual
|
||||
void stop()
|
||||
{
|
||||
assert(state == State::STARTED);
|
||||
// Called whenever a hook is stopped; after threads are destoyed.
|
||||
virtual void stop() {
|
||||
assert(state == State::STARTED);
|
||||
|
||||
state = State::STOPPED;
|
||||
}
|
||||
state = State::STOPPED;
|
||||
}
|
||||
|
||||
virtual
|
||||
void check()
|
||||
{
|
||||
assert(state == State::PARSED);
|
||||
virtual void check() {
|
||||
assert(state == State::PARSED);
|
||||
|
||||
state = State::CHECKED;
|
||||
}
|
||||
state = State::CHECKED;
|
||||
}
|
||||
|
||||
virtual
|
||||
void prepare()
|
||||
{
|
||||
assert(state == State::CHECKED);
|
||||
virtual void prepare() {
|
||||
assert(state == State::CHECKED);
|
||||
|
||||
state = State::PREPARED;
|
||||
}
|
||||
state = State::PREPARED;
|
||||
}
|
||||
|
||||
// Called periodically. Period is set by global 'stats' option in the configuration file.
|
||||
virtual
|
||||
void periodic()
|
||||
{
|
||||
assert(state == State::STARTED);
|
||||
}
|
||||
// Called periodically. Period is set by global 'stats' option in the configuration file.
|
||||
virtual void periodic() { assert(state == State::STARTED); }
|
||||
|
||||
// Called whenever a new simulation case is started. This is detected by a sequence no equal to zero.
|
||||
virtual
|
||||
void restart()
|
||||
{
|
||||
assert(state == State::STARTED);
|
||||
}
|
||||
// Called whenever a new simulation case is started. This is detected by a sequence no equal to zero.
|
||||
virtual void restart() { assert(state == State::STARTED); }
|
||||
|
||||
// Called whenever a sample is processed.
|
||||
virtual
|
||||
Reason process(struct Sample *smp)
|
||||
{
|
||||
return Reason::OK;
|
||||
};
|
||||
// Called whenever a sample is processed.
|
||||
virtual Reason process(struct Sample *smp) { return Reason::OK; };
|
||||
|
||||
unsigned getPriority() const
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
unsigned getPriority() const { return priority; }
|
||||
|
||||
int getFlags() const
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
int getFlags() const { return flags; }
|
||||
|
||||
virtual
|
||||
SignalList::Ptr getSignals() const
|
||||
{
|
||||
return signals;
|
||||
}
|
||||
virtual SignalList::Ptr getSignals() const { return signals; }
|
||||
|
||||
json_t * getConfig() const
|
||||
{
|
||||
return config;
|
||||
}
|
||||
json_t *getConfig() const { return config; }
|
||||
|
||||
HookFactory * getFactory() const
|
||||
{
|
||||
return factory;
|
||||
}
|
||||
HookFactory *getFactory() const { return factory; }
|
||||
|
||||
bool isEnabled() const
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
bool isEnabled() const { return enabled; }
|
||||
};
|
||||
|
||||
class SingleSignalHook : public Hook {
|
||||
|
||||
protected:
|
||||
unsigned signalIndex;
|
||||
std::string signalName;
|
||||
unsigned signalIndex;
|
||||
std::string signalName;
|
||||
|
||||
public:
|
||||
SingleSignalHook(Path *p, Node *n, int fl, int prio, bool en = true) :
|
||||
Hook(p, n, fl, prio, en),
|
||||
signalIndex(0)
|
||||
{ }
|
||||
SingleSignalHook(Path *p, Node *n, int fl, int prio, bool en = true)
|
||||
: Hook(p, n, fl, prio, en), signalIndex(0) {}
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
|
||||
virtual
|
||||
void prepare();
|
||||
virtual void prepare();
|
||||
};
|
||||
|
||||
class MultiSignalHook : public Hook {
|
||||
|
||||
protected:
|
||||
std::list<unsigned> signalIndices;
|
||||
std::vector<std::string> signalNames;
|
||||
std::list<unsigned> signalIndices;
|
||||
std::vector<std::string> signalNames;
|
||||
|
||||
public:
|
||||
using Hook::Hook;
|
||||
using Hook::Hook;
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
|
||||
virtual
|
||||
void prepare();
|
||||
virtual void prepare();
|
||||
|
||||
virtual
|
||||
void check();
|
||||
virtual void check();
|
||||
};
|
||||
|
||||
class LimitHook : public Hook {
|
||||
|
||||
public:
|
||||
using Ptr = std::shared_ptr<LimitHook>;
|
||||
using Hook::Hook;
|
||||
using Ptr = std::shared_ptr<LimitHook>;
|
||||
using Hook::Hook;
|
||||
|
||||
virtual
|
||||
void setRate(double rate, double maxRate = -1) = 0;
|
||||
virtual void setRate(double rate, double maxRate = -1) = 0;
|
||||
|
||||
virtual
|
||||
void parse()
|
||||
{
|
||||
assert(state == State::INITIALIZED);
|
||||
virtual void parse() {
|
||||
assert(state == State::INITIALIZED);
|
||||
|
||||
state = State::PARSED;
|
||||
}
|
||||
state = State::PARSED;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
parse();
|
||||
check();
|
||||
prepare();
|
||||
start();
|
||||
}
|
||||
void init() {
|
||||
parse();
|
||||
check();
|
||||
prepare();
|
||||
start();
|
||||
}
|
||||
};
|
||||
|
||||
class HookFactory : public plugin::Plugin {
|
||||
|
||||
protected:
|
||||
virtual
|
||||
void init(Hook::Ptr h)
|
||||
{
|
||||
h->logger = getLogger();
|
||||
h->factory = this;
|
||||
}
|
||||
virtual void init(Hook::Ptr h) {
|
||||
h->logger = getLogger();
|
||||
h->factory = this;
|
||||
}
|
||||
|
||||
public:
|
||||
using plugin::Plugin::Plugin;
|
||||
using plugin::Plugin::Plugin;
|
||||
|
||||
virtual
|
||||
Hook::Ptr make(Path *p, Node *n) = 0;
|
||||
virtual Hook::Ptr make(Path *p, Node *n) = 0;
|
||||
|
||||
virtual
|
||||
int getFlags() const = 0;
|
||||
virtual int getFlags() const = 0;
|
||||
|
||||
virtual
|
||||
unsigned getPriority() const = 0;
|
||||
virtual unsigned getPriority() const = 0;
|
||||
|
||||
virtual
|
||||
std::string getType() const
|
||||
{
|
||||
return "hook";
|
||||
}
|
||||
virtual std::string getType() const { return "hook"; }
|
||||
|
||||
virtual
|
||||
bool isHidden() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool isHidden() const { return false; }
|
||||
};
|
||||
|
||||
template <typename T, const char *name, const char *desc, int flags = 0, unsigned prio = 99>
|
||||
template <typename T, const char *name, const char *desc, int flags = 0,
|
||||
unsigned prio = 99>
|
||||
class HookPlugin : public HookFactory {
|
||||
|
||||
public:
|
||||
using HookFactory::HookFactory;
|
||||
using HookFactory::HookFactory;
|
||||
|
||||
virtual
|
||||
Hook::Ptr make(Path *p, Node *n)
|
||||
{
|
||||
auto h = std::make_shared<T>(p, n, getFlags(), getPriority());
|
||||
virtual Hook::Ptr make(Path *p, Node *n) {
|
||||
auto h = std::make_shared<T>(p, n, getFlags(), getPriority());
|
||||
|
||||
init(h);
|
||||
init(h);
|
||||
|
||||
return h;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
virtual std::string getName() const { return name; }
|
||||
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
virtual std::string getDescription() const { return desc; }
|
||||
|
||||
virtual
|
||||
int getFlags() const
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
virtual int getFlags() const { return flags; }
|
||||
|
||||
virtual
|
||||
unsigned getPriority() const
|
||||
{
|
||||
return prio;
|
||||
}
|
||||
virtual unsigned getPriority() const { return prio; }
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -24,10 +24,9 @@ struct Sample;
|
|||
class HookList : public std::list<Hook::Ptr> {
|
||||
|
||||
public:
|
||||
HookList()
|
||||
{ }
|
||||
HookList() {}
|
||||
|
||||
/* Parses an object of hooks
|
||||
/* Parses an object of hooks
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
|
@ -41,25 +40,25 @@ public:
|
|||
* hooks = [ "print" ]
|
||||
* }
|
||||
*/
|
||||
void parse(json_t *json, int mask, Path *p, Node *n);
|
||||
void parse(json_t *json, int mask, Path *p, Node *n);
|
||||
|
||||
void check();
|
||||
void check();
|
||||
|
||||
void prepare(SignalList::Ptr sigs, int mask, Path *p, Node *n);
|
||||
void prepare(SignalList::Ptr sigs, int mask, Path *p, Node *n);
|
||||
|
||||
int process(struct Sample *smps[], unsigned cnt);
|
||||
void periodic();
|
||||
void start();
|
||||
void stop();
|
||||
int process(struct Sample *smps[], unsigned cnt);
|
||||
void periodic();
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
void dump(villas::Logger logger, std::string subject) const;
|
||||
void dump(villas::Logger logger, std::string subject) const;
|
||||
|
||||
SignalList::Ptr getSignals() const;
|
||||
SignalList::Ptr getSignals() const;
|
||||
|
||||
// Get the maximum number of signals which is used by any of the hooks in the list.
|
||||
unsigned getSignalsMaxCount() const;
|
||||
// Get the maximum number of signals which is used by any of the hooks in the list.
|
||||
unsigned getSignalsMaxCount() const;
|
||||
|
||||
json_t * toJson() const;
|
||||
json_t *toJson() const;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -15,38 +15,30 @@ namespace node {
|
|||
class DecimateHook : public LimitHook {
|
||||
|
||||
protected:
|
||||
int ratio;
|
||||
bool renumber;
|
||||
unsigned counter;
|
||||
int ratio;
|
||||
bool renumber;
|
||||
unsigned counter;
|
||||
|
||||
public:
|
||||
using LimitHook::LimitHook;
|
||||
using LimitHook::LimitHook;
|
||||
|
||||
virtual
|
||||
void setRate(double rate, double maxRate = -1)
|
||||
{
|
||||
assert(maxRate > 0);
|
||||
virtual void setRate(double rate, double maxRate = -1) {
|
||||
assert(maxRate > 0);
|
||||
|
||||
int ratio = maxRate / rate;
|
||||
if (ratio == 0)
|
||||
ratio = 1;
|
||||
int ratio = maxRate / rate;
|
||||
if (ratio == 0)
|
||||
ratio = 1;
|
||||
|
||||
setRatio(ratio);
|
||||
}
|
||||
setRatio(ratio);
|
||||
}
|
||||
|
||||
void setRatio(int r)
|
||||
{
|
||||
ratio = r;
|
||||
}
|
||||
void setRatio(int r) { ratio = r; }
|
||||
|
||||
virtual
|
||||
void start();
|
||||
virtual void start();
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
|
||||
virtual
|
||||
Hook::Reason process(struct Sample *smp);
|
||||
virtual Hook::Reason process(struct Sample *smp);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -15,35 +15,24 @@ namespace node {
|
|||
class LimitRateHook : public LimitHook {
|
||||
|
||||
protected:
|
||||
// The timestamp which should be used for limiting.
|
||||
enum {
|
||||
LIMIT_RATE_LOCAL,
|
||||
LIMIT_RATE_RECEIVED,
|
||||
LIMIT_RATE_ORIGIN
|
||||
} mode;
|
||||
// The timestamp which should be used for limiting.
|
||||
enum { LIMIT_RATE_LOCAL, LIMIT_RATE_RECEIVED, LIMIT_RATE_ORIGIN } mode;
|
||||
|
||||
double deadtime;
|
||||
timespec last;
|
||||
double deadtime;
|
||||
timespec last;
|
||||
|
||||
public:
|
||||
LimitRateHook(Path *p, Node *n, int fl, int prio, bool en = true) :
|
||||
LimitHook(p, n, fl, prio, en),
|
||||
mode(LIMIT_RATE_LOCAL),
|
||||
deadtime(0),
|
||||
last({0, 0})
|
||||
{ }
|
||||
LimitRateHook(Path *p, Node *n, int fl, int prio, bool en = true)
|
||||
: LimitHook(p, n, fl, prio, en), mode(LIMIT_RATE_LOCAL), deadtime(0),
|
||||
last({0, 0}) {}
|
||||
|
||||
virtual
|
||||
void setRate(double rate, double maxRate = -1)
|
||||
{
|
||||
deadtime = 1.0 / rate;
|
||||
}
|
||||
virtual void setRate(double rate, double maxRate = -1) {
|
||||
deadtime = 1.0 / rate;
|
||||
}
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
|
||||
virtual
|
||||
Hook::Reason process(struct Sample *smp);
|
||||
virtual Hook::Reason process(struct Sample *smp);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <villas/hook.hpp>
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lua.h"
|
||||
};
|
||||
|
||||
namespace villas {
|
||||
|
@ -26,115 +26,105 @@ enum SignalType;
|
|||
class LuaSignalExpression {
|
||||
|
||||
protected:
|
||||
int cookie;
|
||||
lua_State *L;
|
||||
int cookie;
|
||||
lua_State *L;
|
||||
|
||||
std::string expression;
|
||||
std::string expression;
|
||||
|
||||
json_t *cfg;
|
||||
json_t *cfg;
|
||||
|
||||
public:
|
||||
LuaSignalExpression(lua_State *L, json_t *json_sig);
|
||||
LuaSignalExpression(lua_State *L, json_t *json_sig);
|
||||
|
||||
void prepare();
|
||||
void prepare();
|
||||
|
||||
void parseExpression(const std::string &expr);
|
||||
void parseExpression(const std::string &expr);
|
||||
|
||||
void evaluate(union SignalData *data, enum SignalType type);
|
||||
void evaluate(union SignalData *data, enum SignalType type);
|
||||
};
|
||||
|
||||
class LuaHook : public Hook {
|
||||
|
||||
friend LuaSignalExpression;
|
||||
friend LuaSignalExpression;
|
||||
|
||||
private:
|
||||
static
|
||||
const int SELF_REFERENCE = 55;
|
||||
static const int SELF_REFERENCE = 55;
|
||||
|
||||
protected:
|
||||
std::string script;
|
||||
std::vector<LuaSignalExpression> expressions;
|
||||
std::string script;
|
||||
std::vector<LuaSignalExpression> expressions;
|
||||
|
||||
SignalList::Ptr signalsProcessed; // Signals as emited by Lua process() function
|
||||
SignalList::Ptr signalsExpressions; // Signals as emited by Lua expressions
|
||||
SignalList::Ptr
|
||||
signalsProcessed; // Signals as emited by Lua process() function
|
||||
SignalList::Ptr signalsExpressions; // Signals as emited by Lua expressions
|
||||
|
||||
lua_State *L;
|
||||
std::mutex mutex;
|
||||
lua_State *L;
|
||||
std::mutex mutex;
|
||||
|
||||
bool useNames;
|
||||
bool hasExpressions;
|
||||
bool needsLocking;
|
||||
bool useNames;
|
||||
bool hasExpressions;
|
||||
bool needsLocking;
|
||||
|
||||
// Function indices
|
||||
struct {
|
||||
int start;
|
||||
int stop;
|
||||
int restart;
|
||||
int process;
|
||||
int periodic;
|
||||
int prepare;
|
||||
} functions;
|
||||
// Function indices
|
||||
struct {
|
||||
int start;
|
||||
int stop;
|
||||
int restart;
|
||||
int process;
|
||||
int periodic;
|
||||
int prepare;
|
||||
} functions;
|
||||
|
||||
void parseExpressions(json_t *json_sigs);
|
||||
void parseExpressions(json_t *json_sigs);
|
||||
|
||||
void loadScript();
|
||||
void lookupFunctions();
|
||||
void setupEnvironment();
|
||||
void loadScript();
|
||||
void lookupFunctions();
|
||||
void setupEnvironment();
|
||||
|
||||
// Lua functions
|
||||
// Lua functions
|
||||
|
||||
int luaInfo(lua_State *L);
|
||||
int luaWarn(lua_State *L);
|
||||
int luaError(lua_State *L);
|
||||
int luaDebug(lua_State *L);
|
||||
int luaInfo(lua_State *L);
|
||||
int luaWarn(lua_State *L);
|
||||
int luaError(lua_State *L);
|
||||
int luaDebug(lua_State *L);
|
||||
|
||||
int luaRegisterApiHandler(lua_State *L);
|
||||
int luaRegisterApiHandler(lua_State *L);
|
||||
|
||||
typedef int (LuaHook::*mem_func)(lua_State * L);
|
||||
typedef int (LuaHook::*mem_func)(lua_State *L);
|
||||
|
||||
// This template wraps a member function into a C-style "free" function compatible with lua.
|
||||
template <mem_func func>
|
||||
static
|
||||
int dispatch(lua_State * L) {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, SELF_REFERENCE);
|
||||
void *vptr = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
// This template wraps a member function into a C-style "free" function compatible with lua.
|
||||
template <mem_func func> static int dispatch(lua_State *L) {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, SELF_REFERENCE);
|
||||
void *vptr = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
LuaHook *ptr = static_cast<LuaHook*>(vptr);
|
||||
return ((*ptr).*func)(L);
|
||||
}
|
||||
LuaHook *ptr = static_cast<LuaHook *>(vptr);
|
||||
return ((*ptr).*func)(L);
|
||||
}
|
||||
|
||||
public:
|
||||
LuaHook(Path *p, Node *n, int fl, int prio, bool en = true);
|
||||
LuaHook(Path *p, Node *n, int fl, int prio, bool en = true);
|
||||
|
||||
virtual
|
||||
~LuaHook();
|
||||
virtual ~LuaHook();
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
|
||||
virtual
|
||||
void prepare();
|
||||
virtual void prepare();
|
||||
|
||||
// Periodically called by the main thread.
|
||||
virtual
|
||||
void periodic();
|
||||
// Periodically called by the main thread.
|
||||
virtual void periodic();
|
||||
|
||||
// Called whenever a hook is started; before threads are created.
|
||||
virtual
|
||||
void start();
|
||||
// Called whenever a hook is started; before threads are created.
|
||||
virtual void start();
|
||||
|
||||
// Called whenever a hook is stopped; after threads are destoyed.
|
||||
virtual
|
||||
void stop();
|
||||
// Called whenever a hook is stopped; after threads are destoyed.
|
||||
virtual void stop();
|
||||
|
||||
// Called whenever a new simulation case is started. This is detected by a sequence no equal to zero.
|
||||
virtual
|
||||
void restart();
|
||||
// Called whenever a new simulation case is started. This is detected by a sequence no equal to zero.
|
||||
virtual void restart();
|
||||
|
||||
// Called whenever a sample is processed.
|
||||
virtual
|
||||
Reason process(struct Sample *smp);
|
||||
// Called whenever a sample is processed.
|
||||
virtual Reason process(struct Sample *smp);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -15,72 +15,59 @@ namespace node {
|
|||
class PmuHook : public MultiSignalHook {
|
||||
|
||||
protected:
|
||||
enum class Status {
|
||||
INVALID,
|
||||
VALID
|
||||
};
|
||||
enum class Status { INVALID, VALID };
|
||||
|
||||
struct Phasor {
|
||||
double frequency;
|
||||
double amplitude;
|
||||
double phase;
|
||||
double rocof; // Rate of change of frequency.
|
||||
Status valid;
|
||||
};
|
||||
struct Phasor {
|
||||
double frequency;
|
||||
double amplitude;
|
||||
double phase;
|
||||
double rocof; // Rate of change of frequency.
|
||||
Status valid;
|
||||
};
|
||||
|
||||
enum class WindowType {
|
||||
NONE,
|
||||
FLATTOP,
|
||||
HANN,
|
||||
HAMMING,
|
||||
NUTTAL,
|
||||
BLACKMAN
|
||||
};
|
||||
enum class WindowType { NONE, FLATTOP, HANN, HAMMING, NUTTAL, BLACKMAN };
|
||||
|
||||
enum class TimeAlign {
|
||||
LEFT,
|
||||
CENTER,
|
||||
RIGHT,
|
||||
};
|
||||
enum class TimeAlign {
|
||||
LEFT,
|
||||
CENTER,
|
||||
RIGHT,
|
||||
};
|
||||
|
||||
std::vector<dsp::CosineWindow<double>*> windows;
|
||||
dsp::Window<timespec> *windowsTs;
|
||||
std::vector<Phasor> lastPhasors;
|
||||
std::vector<dsp::CosineWindow<double> *> windows;
|
||||
dsp::Window<timespec> *windowsTs;
|
||||
std::vector<Phasor> lastPhasors;
|
||||
|
||||
enum TimeAlign timeAlignType;
|
||||
enum WindowType windowType;
|
||||
enum TimeAlign timeAlignType;
|
||||
enum WindowType windowType;
|
||||
|
||||
unsigned sampleRate;
|
||||
double phasorRate;
|
||||
double nominalFreq;
|
||||
double numberPlc;
|
||||
unsigned windowSize;
|
||||
bool channelNameEnable;
|
||||
double angleUnitFactor;
|
||||
uint64_t lastSequence;
|
||||
timespec nextRun;
|
||||
bool init;
|
||||
unsigned initSampleCount;
|
||||
// Correction factors.
|
||||
double phaseOffset;
|
||||
double amplitudeOffset;
|
||||
double frequencyOffset;
|
||||
double rocofOffset;
|
||||
unsigned sampleRate;
|
||||
double phasorRate;
|
||||
double nominalFreq;
|
||||
double numberPlc;
|
||||
unsigned windowSize;
|
||||
bool channelNameEnable;
|
||||
double angleUnitFactor;
|
||||
uint64_t lastSequence;
|
||||
timespec nextRun;
|
||||
bool init;
|
||||
unsigned initSampleCount;
|
||||
// Correction factors.
|
||||
double phaseOffset;
|
||||
double amplitudeOffset;
|
||||
double frequencyOffset;
|
||||
double rocofOffset;
|
||||
|
||||
public:
|
||||
PmuHook(Path *p, Node *n, int fl, int prio, bool en = true);
|
||||
PmuHook(Path *p, Node *n, int fl, int prio, bool en = true);
|
||||
|
||||
virtual
|
||||
void prepare();
|
||||
virtual void prepare();
|
||||
|
||||
virtual
|
||||
void parse(json_t *json);
|
||||
virtual void parse(json_t *json);
|
||||
|
||||
virtual
|
||||
Hook::Reason process(struct Sample *smp);
|
||||
virtual Hook::Reason process(struct Sample *smp);
|
||||
|
||||
virtual
|
||||
Phasor estimatePhasor(dsp::CosineWindow<double> *window, Phasor lastPhasor);
|
||||
virtual Phasor estimatePhasor(dsp::CosineWindow<double> *window,
|
||||
Phasor lastPhasor);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -12,13 +12,14 @@
|
|||
|
||||
#include <list>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <villas/log.hpp>
|
||||
|
||||
#ifndef SO_MARK
|
||||
#define SO_MARK 36 // Workaround: add missing constant for OPAL-RT Redhawk target
|
||||
#define SO_MARK \
|
||||
36 // Workaround: add missing constant for OPAL-RT Redhawk target
|
||||
#endif
|
||||
|
||||
// Forward declarations
|
||||
|
@ -33,7 +34,7 @@ namespace node {
|
|||
class Node;
|
||||
class SuperNode;
|
||||
|
||||
}
|
||||
} // namespace node
|
||||
|
||||
namespace kernel {
|
||||
|
||||
|
@ -41,23 +42,24 @@ namespace kernel {
|
|||
class Interface {
|
||||
|
||||
public:
|
||||
struct rtnl_link *nl_link; // libnl3: Handle of interface.
|
||||
struct rtnl_qdisc *tc_qdisc; // libnl3: Root priority queuing discipline (qdisc).
|
||||
struct rtnl_link *nl_link; // libnl3: Handle of interface.
|
||||
struct rtnl_qdisc
|
||||
*tc_qdisc; // libnl3: Root priority queuing discipline (qdisc).
|
||||
|
||||
protected:
|
||||
int affinity; // IRQ / Core Affinity of this interface.
|
||||
int affinity; // IRQ / Core Affinity of this interface.
|
||||
|
||||
std::list<int> irqs; // List of IRQs of the NIC.
|
||||
std::list<node::Node *> nodes; // List of nodes which use this interface.
|
||||
std::list<int> irqs; // List of IRQs of the NIC.
|
||||
std::list<node::Node *> nodes; // List of nodes which use this interface.
|
||||
|
||||
Logger logger;
|
||||
Logger logger;
|
||||
|
||||
public:
|
||||
// Add a new interface to the global list and lookup name, irqs...
|
||||
Interface(struct rtnl_link *link, int affinity = 0);
|
||||
~Interface();
|
||||
// Add a new interface to the global list and lookup name, irqs...
|
||||
Interface(struct rtnl_link *link, int affinity = 0);
|
||||
~Interface();
|
||||
|
||||
/* Start interface.
|
||||
/* Start interface.
|
||||
*
|
||||
* This setups traffic controls queue discs, network emulation and
|
||||
* maps interface IRQs according to affinity.
|
||||
|
@ -66,9 +68,9 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int start();
|
||||
int start();
|
||||
|
||||
/* Stop interface
|
||||
/* Stop interface
|
||||
*
|
||||
* This resets traffic qdiscs ant network emulation
|
||||
* and maps interface IRQs to all CPUs.
|
||||
|
@ -77,16 +79,14 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int stop();
|
||||
int stop();
|
||||
|
||||
/* Find existing or create new interface instance on which packets for a certain destination
|
||||
/* Find existing or create new interface instance on which packets for a certain destination
|
||||
* will leave the system.
|
||||
*/
|
||||
static
|
||||
Interface *
|
||||
getEgress(struct sockaddr *sa, node::SuperNode *sn);
|
||||
static Interface *getEgress(struct sockaddr *sa, node::SuperNode *sn);
|
||||
|
||||
/* Get all IRQs for this interface.
|
||||
/* Get all IRQs for this interface.
|
||||
*
|
||||
* Only MSI IRQs are determined by looking at:
|
||||
* /sys/class/net/{ifname}/device/msi_irqs/
|
||||
|
@ -95,23 +95,20 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int getIRQs();
|
||||
int getIRQs();
|
||||
|
||||
/* Change the SMP affinity of NIC interrupts.
|
||||
/* Change the SMP affinity of NIC interrupts.
|
||||
*
|
||||
* @param i A pointer to the interface structure
|
||||
* @param affinity A mask specifying which cores should handle this interrupt.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int setAffinity(int affinity);
|
||||
int setAffinity(int affinity);
|
||||
|
||||
std::string getName() const;
|
||||
std::string getName() const;
|
||||
|
||||
void addNode(node::Node *n)
|
||||
{
|
||||
nodes.push_back(n);
|
||||
}
|
||||
void addNode(node::Node *n) { nodes.push_back(n); }
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
|
|
|
@ -16,44 +16,39 @@ extern "C" {
|
|||
|
||||
#define SCH_NETEM_ATTR_DIST 0x2000
|
||||
|
||||
struct rtnl_netem_corr
|
||||
{
|
||||
uint32_t nmc_delay;
|
||||
uint32_t nmc_loss;
|
||||
uint32_t nmc_duplicate;
|
||||
struct rtnl_netem_corr {
|
||||
uint32_t nmc_delay;
|
||||
uint32_t nmc_loss;
|
||||
uint32_t nmc_duplicate;
|
||||
};
|
||||
|
||||
struct rtnl_netem_reo
|
||||
{
|
||||
uint32_t nmro_probability;
|
||||
uint32_t nmro_correlation;
|
||||
struct rtnl_netem_reo {
|
||||
uint32_t nmro_probability;
|
||||
uint32_t nmro_correlation;
|
||||
};
|
||||
|
||||
struct rtnl_netem_crpt
|
||||
{
|
||||
uint32_t nmcr_probability;
|
||||
uint32_t nmcr_correlation;
|
||||
struct rtnl_netem_crpt {
|
||||
uint32_t nmcr_probability;
|
||||
uint32_t nmcr_correlation;
|
||||
};
|
||||
|
||||
struct rtnl_netem_dist
|
||||
{
|
||||
int16_t * dist_data;
|
||||
size_t dist_size;
|
||||
struct rtnl_netem_dist {
|
||||
int16_t *dist_data;
|
||||
size_t dist_size;
|
||||
};
|
||||
|
||||
struct rtnl_netem
|
||||
{
|
||||
uint32_t qnm_latency;
|
||||
uint32_t qnm_limit;
|
||||
uint32_t qnm_loss;
|
||||
uint32_t qnm_gap;
|
||||
uint32_t qnm_duplicate;
|
||||
uint32_t qnm_jitter;
|
||||
uint32_t qnm_mask;
|
||||
struct rtnl_netem_corr qnm_corr;
|
||||
struct rtnl_netem_reo qnm_ro;
|
||||
struct rtnl_netem_crpt qnm_crpt;
|
||||
struct rtnl_netem_dist qnm_dist;
|
||||
struct rtnl_netem {
|
||||
uint32_t qnm_latency;
|
||||
uint32_t qnm_limit;
|
||||
uint32_t qnm_loss;
|
||||
uint32_t qnm_gap;
|
||||
uint32_t qnm_duplicate;
|
||||
uint32_t qnm_jitter;
|
||||
uint32_t qnm_mask;
|
||||
struct rtnl_netem_corr qnm_corr;
|
||||
struct rtnl_netem_reo qnm_ro;
|
||||
struct rtnl_netem_crpt qnm_crpt;
|
||||
struct rtnl_netem_dist qnm_dist;
|
||||
};
|
||||
|
||||
void *rtnl_tc_data(struct rtnl_tc *tc);
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#include <sys/socket.h>
|
||||
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/route/route.h>
|
||||
#include <netlink/route/link.h>
|
||||
#include <netlink/route/route.h>
|
||||
|
||||
namespace villas {
|
||||
namespace kernel {
|
||||
|
@ -32,10 +32,10 @@ int get_egress(struct nl_addr *addr);
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
struct rtnl_link * get_egress_link(struct sockaddr *sa);
|
||||
struct rtnl_link *get_egress_link(struct sockaddr *sa);
|
||||
|
||||
// Get or create global netlink socket.
|
||||
struct nl_sock * init();
|
||||
struct nl_sock *init();
|
||||
|
||||
// Close and free global netlink socket.
|
||||
void shutdown();
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
#include <netlink/route/qdisc.h>
|
||||
#include <netlink/route/classifier.h>
|
||||
#include <netlink/route/qdisc.h>
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
@ -47,7 +47,8 @@ int reset(Interface *i);
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int prio(Interface *i, struct rtnl_qdisc **qd, tc_hdl_t handle, tc_hdl_t, int bands);
|
||||
int prio(Interface *i, struct rtnl_qdisc **qd, tc_hdl_t handle, tc_hdl_t,
|
||||
int bands);
|
||||
|
||||
/* Add a new filter based on the netfilter mark.
|
||||
*
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
#include <netlink/route/qdisc.h>
|
||||
#include <netlink/route/classifier.h>
|
||||
#include <netlink/route/qdisc.h>
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
@ -43,7 +43,7 @@ int netem_parse(struct rtnl_qdisc **ne, json_t *json);
|
|||
* @param tc A pointer to the libnl3 qdisc object where settings will be read from.
|
||||
* @return A pointer to a string which must be freed() by the caller.
|
||||
*/
|
||||
char * netem_print(struct rtnl_qdisc *ne);
|
||||
char *netem_print(struct rtnl_qdisc *ne);
|
||||
|
||||
/* Add a new network emulator (netem) discipline.
|
||||
*
|
||||
|
@ -54,7 +54,8 @@ char * netem_print(struct rtnl_qdisc *ne);
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int netem(Interface *i, struct rtnl_qdisc **qd, tc_hdl_t handle, tc_hdl_t parent);
|
||||
int netem(Interface *i, struct rtnl_qdisc **qd, tc_hdl_t handle,
|
||||
tc_hdl_t parent);
|
||||
|
||||
int netem_set_delay_distribution(struct rtnl_qdisc *qdisc, json_t *json);
|
||||
|
||||
|
|
|
@ -9,44 +9,41 @@
|
|||
|
||||
#include <mutex>
|
||||
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/config.hpp>
|
||||
#include <villas/log.hpp>
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
|
||||
extern "C" {
|
||||
/* Define RTLAB before including OpalPrint.h for messages to be sent
|
||||
/* Define RTLAB before including OpalPrint.h for messages to be sent
|
||||
* to the OpalDisplay. Otherwise stdout will be used. */
|
||||
#define RTLAB
|
||||
#include <OpalPrint.h>
|
||||
#define RTLAB
|
||||
#include <OpalPrint.h>
|
||||
}
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
||||
template<typename Mutex>
|
||||
class OpalSink : public spdlog::sinks::base_sink<Mutex>
|
||||
{
|
||||
template <typename Mutex>
|
||||
class OpalSink : public spdlog::sinks::base_sink<Mutex> {
|
||||
|
||||
protected:
|
||||
void sink_it_(const spdlog::details::log_msg &msg) override
|
||||
{
|
||||
void sink_it_(const spdlog::details::log_msg &msg) override {
|
||||
#ifdef WITH_NODE_OPAL
|
||||
fmt::memory_buffer formatted;
|
||||
fmt::memory_buffer formatted;
|
||||
|
||||
sink::formatter_->format(msg, formatted);
|
||||
sink::formatter_->format(msg, formatted);
|
||||
|
||||
auto str = fmt::to_string(formatted).c_str();
|
||||
auto str = fmt::to_string(formatted).c_str();
|
||||
|
||||
OpalPrint(PROJECT_NAME ": %s\n", str);
|
||||
OpalPrint(PROJECT_NAME ": %s\n", str);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void flush_() override
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
void flush_() override {
|
||||
// nothing to do
|
||||
}
|
||||
};
|
||||
|
||||
using OpalSink_mt = OpalSink<std::mutex>;
|
||||
|
|
|
@ -11,18 +11,21 @@
|
|||
#include <memory>
|
||||
|
||||
#include <villas/common.hpp>
|
||||
#include <villas/stats.hpp>
|
||||
#include <villas/node_list.hpp>
|
||||
#include <villas/stats.hpp>
|
||||
|
||||
#define RE_MAPPING_INDEX "[a-zA-Z0-9_]+"
|
||||
#define RE_MAPPING_RANGE "(" RE_MAPPING_INDEX ")(?:-(" RE_MAPPING_INDEX "))?"
|
||||
|
||||
#define RE_MAPPING_STATS "stats\\.([a-z]+)\\.([a-z]+)"
|
||||
#define RE_MAPPING_HDR "hdr\\.(sequence|length)"
|
||||
#define RE_MAPPING_TS "ts\\.(origin|received)"
|
||||
#define RE_MAPPING_HDR "hdr\\.(sequence|length)"
|
||||
#define RE_MAPPING_TS "ts\\.(origin|received)"
|
||||
#define RE_MAPPING_DATA1 "data\\[" RE_MAPPING_RANGE "\\]"
|
||||
#define RE_MAPPING_DATA2 "(?:data\\.)?(" RE_MAPPING_INDEX ")"
|
||||
#define RE_MAPPING "(?:(" RE_NODE_NAME ")\\.(?:" RE_MAPPING_STATS "|" RE_MAPPING_HDR "|" RE_MAPPING_TS "|" RE_MAPPING_DATA1 "|" RE_MAPPING_DATA2 ")|(" RE_NODE_NAME ")(?:\\[" RE_MAPPING_RANGE "\\])?)"
|
||||
#define RE_MAPPING \
|
||||
"(?:(" RE_NODE_NAME ")\\.(?:" RE_MAPPING_STATS "|" RE_MAPPING_HDR \
|
||||
"|" RE_MAPPING_TS "|" RE_MAPPING_DATA1 "|" RE_MAPPING_DATA2 \
|
||||
")|(" RE_NODE_NAME ")(?:\\[" RE_MAPPING_RANGE "\\])?)"
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -35,74 +38,62 @@ class Signal;
|
|||
class MappingEntry {
|
||||
|
||||
public:
|
||||
using Ptr = std::shared_ptr<MappingEntry>;
|
||||
using Ptr = std::shared_ptr<MappingEntry>;
|
||||
|
||||
enum class Type {
|
||||
UNKNOWN,
|
||||
DATA,
|
||||
STATS,
|
||||
HEADER,
|
||||
TIMESTAMP
|
||||
};
|
||||
enum class Type { UNKNOWN, DATA, STATS, HEADER, TIMESTAMP };
|
||||
|
||||
enum class HeaderType {
|
||||
LENGTH,
|
||||
SEQUENCE
|
||||
};
|
||||
enum class HeaderType { LENGTH, SEQUENCE };
|
||||
|
||||
enum class TimestampType {
|
||||
ORIGIN,
|
||||
RECEIVED
|
||||
};
|
||||
enum class TimestampType { ORIGIN, RECEIVED };
|
||||
|
||||
Node *node; // The node to which this mapping refers.
|
||||
enum Type type; // The mapping type. Selects one of the union fields below.
|
||||
Node *node; // The node to which this mapping refers.
|
||||
enum Type type; // The mapping type. Selects one of the union fields below.
|
||||
|
||||
/* The number of values which is covered by this mapping entry.
|
||||
/* The number of values which is covered by this 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
|
||||
int length;
|
||||
unsigned offset; // Offset of this mapping entry within sample::data
|
||||
|
||||
union {
|
||||
struct {
|
||||
int offset;
|
||||
Signal *signal;
|
||||
union {
|
||||
struct {
|
||||
int offset;
|
||||
Signal *signal;
|
||||
|
||||
char *first;
|
||||
char *last;
|
||||
} data;
|
||||
char *first;
|
||||
char *last;
|
||||
} data;
|
||||
|
||||
struct {
|
||||
enum Stats::Metric metric;
|
||||
enum Stats::Type type;
|
||||
} stats;
|
||||
struct {
|
||||
enum Stats::Metric metric;
|
||||
enum Stats::Type type;
|
||||
} stats;
|
||||
|
||||
struct {
|
||||
enum HeaderType type;
|
||||
} header;
|
||||
struct {
|
||||
enum HeaderType type;
|
||||
} header;
|
||||
|
||||
struct {
|
||||
enum TimestampType type;
|
||||
} timestamp;
|
||||
};
|
||||
struct {
|
||||
enum TimestampType type;
|
||||
} timestamp;
|
||||
};
|
||||
|
||||
std::string nodeName; // Used for between parse and prepare only.
|
||||
std::string nodeName; // Used for between parse and prepare only.
|
||||
|
||||
MappingEntry();
|
||||
MappingEntry();
|
||||
|
||||
int prepare(NodeList &nodes);
|
||||
int prepare(NodeList &nodes);
|
||||
|
||||
int update(struct Sample *remapped, const struct Sample *original) const;
|
||||
int update(struct Sample *remapped, const struct Sample *original) const;
|
||||
|
||||
int parse(json_t *json);
|
||||
int parse(json_t *json);
|
||||
|
||||
int parseString(const std::string &str);
|
||||
int parseString(const std::string &str);
|
||||
|
||||
std::string toString(unsigned index) const;
|
||||
std::string toString(unsigned index) const;
|
||||
|
||||
Signal::Ptr toSignal(unsigned index) const;
|
||||
Signal::Ptr toSignal(unsigned index) const;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -18,13 +18,14 @@ namespace node {
|
|||
class MappingList : public std::list<MappingEntry::Ptr> {
|
||||
|
||||
public:
|
||||
int parse(json_t *json);
|
||||
int parse(json_t *json);
|
||||
|
||||
int prepare(NodeList &nodes);
|
||||
int prepare(NodeList &nodes);
|
||||
|
||||
int remap(struct Sample *remapped, const struct Sample *original) const;
|
||||
int remap(struct Sample *remapped, const struct Sample *original) const;
|
||||
|
||||
int update(const MappingEntry::Ptr me, struct Sample *remapped, const struct Sample *original);
|
||||
int update(const MappingEntry::Ptr me, struct Sample *remapped,
|
||||
const struct Sample *original);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -14,11 +14,11 @@ namespace node {
|
|||
namespace memory {
|
||||
|
||||
struct IB {
|
||||
struct ibv_pd *pd;
|
||||
struct Type *parent;
|
||||
struct ibv_pd *pd;
|
||||
struct Type *parent;
|
||||
};
|
||||
|
||||
struct ibv_mr * ib_get_mr(void *ptr);
|
||||
struct ibv_mr *ib_get_mr(void *ptr);
|
||||
|
||||
} // namespace memory
|
||||
} // namespace node
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
typedef void *vnode;
|
||||
typedef void *vsample;
|
||||
|
||||
vnode * node_new(const char *id_str, const char *json_str);
|
||||
vnode *node_new(const char *id_str, const char *json_str);
|
||||
|
||||
int node_prepare(vnode *n);
|
||||
|
||||
|
@ -32,13 +32,13 @@ int node_restart(vnode *n);
|
|||
|
||||
int node_destroy(vnode *n);
|
||||
|
||||
const char * node_name(vnode *n);
|
||||
const char *node_name(vnode *n);
|
||||
|
||||
const char * node_name_short(vnode *n);
|
||||
const char *node_name_short(vnode *n);
|
||||
|
||||
const char * node_name_full(vnode *n);
|
||||
const char *node_name_full(vnode *n);
|
||||
|
||||
const char * node_details(vnode *n);
|
||||
const char *node_details(vnode *n);
|
||||
|
||||
unsigned node_input_signals_max_cnt(vnode *n);
|
||||
|
||||
|
@ -58,18 +58,22 @@ bool node_is_valid_name(const char *name);
|
|||
|
||||
bool node_is_enabled(const vnode *n);
|
||||
|
||||
json_t * node_to_json(const vnode *n);
|
||||
json_t *node_to_json(const vnode *n);
|
||||
|
||||
const char * node_to_json_str(vnode *n);
|
||||
const char *node_to_json_str(vnode *n);
|
||||
|
||||
vsample * sample_alloc(unsigned len);
|
||||
vsample *sample_alloc(unsigned len);
|
||||
|
||||
unsigned sample_length(vsample *smp);
|
||||
|
||||
void sample_decref(vsample *smp);
|
||||
|
||||
vsample * sample_pack(unsigned seq, struct timespec *ts_origin, struct timespec *ts_received, unsigned len, double *values);
|
||||
vsample *sample_pack(unsigned seq, struct timespec *ts_origin,
|
||||
struct timespec *ts_received, unsigned len,
|
||||
double *values);
|
||||
|
||||
void sample_unpack(vsample *s, unsigned *seq, struct timespec *ts_origin, struct timespec *ts_received, int *flags, unsigned *len, double *values);
|
||||
void sample_unpack(vsample *s, unsigned *seq, struct timespec *ts_origin,
|
||||
struct timespec *ts_received, int *flags, unsigned *len,
|
||||
double *values);
|
||||
|
||||
int memory_init(int hugepages);
|
||||
|
|
|
@ -8,31 +8,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <jansson.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <spdlog/fmt/ostr.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include <villas/node_list.hpp>
|
||||
#include <villas/node_direction.hpp>
|
||||
#include <villas/node/memory.hpp>
|
||||
#include <villas/sample.hpp>
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/queue.h>
|
||||
#include <villas/colors.hpp>
|
||||
#include <villas/common.hpp>
|
||||
#include <villas/stats.hpp>
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/plugin.hpp>
|
||||
#include <villas/path_source.hpp>
|
||||
#include <villas/node/memory.hpp>
|
||||
#include <villas/node_direction.hpp>
|
||||
#include <villas/node_list.hpp>
|
||||
#include <villas/path_destination.hpp>
|
||||
#include <villas/path_source.hpp>
|
||||
#include <villas/plugin.hpp>
|
||||
#include <villas/queue.h>
|
||||
#include <villas/sample.hpp>
|
||||
#include <villas/stats.hpp>
|
||||
|
||||
#if defined(LIBNL3_ROUTE_FOUND) && defined(__linux__)
|
||||
#define WITH_NETEM
|
||||
#define WITH_NETEM
|
||||
#endif // LIBNL3_ROUTE_FOUND
|
||||
|
||||
// Forward declarations
|
||||
#ifdef WITH_NETEM
|
||||
struct rtnl_qdisc;
|
||||
struct rtnl_cls;
|
||||
struct rtnl_qdisc;
|
||||
struct rtnl_cls;
|
||||
#endif // WITH_NETEM
|
||||
|
||||
#define RE_NODE_NAME "[a-z0-9_-]{2,32}"
|
||||
|
@ -51,123 +51,102 @@ class SuperNode;
|
|||
*/
|
||||
class Node {
|
||||
|
||||
friend NodeFactory;
|
||||
friend NodeFactory;
|
||||
|
||||
public:
|
||||
Logger logger;
|
||||
Logger logger;
|
||||
|
||||
uint64_t sequence_init;
|
||||
uint64_t sequence; // This is a counter of received samples, in case the node-type does not generate sequence numbers itself.
|
||||
uint64_t sequence_init;
|
||||
uint64_t
|
||||
sequence; // This is a counter of received samples, in case the node-type does not generate sequence numbers itself.
|
||||
|
||||
NodeDirection in, out;
|
||||
NodeDirection in, out;
|
||||
|
||||
PathSourceList sources; // A list of path sources which reference this node.
|
||||
PathDestinationList destinations; // A list of path destinations which reference this node.
|
||||
PathSourceList sources; // A list of path sources which reference this node.
|
||||
PathDestinationList
|
||||
destinations; // A list of path destinations which reference this node.
|
||||
|
||||
#ifdef __linux__
|
||||
int fwmark; // Socket mark for netem, routing and filtering
|
||||
int fwmark; // Socket mark for netem, routing and filtering
|
||||
|
||||
#ifdef WITH_NETEM
|
||||
struct rtnl_qdisc *tc_qdisc; // libnl3: Network emulator queuing discipline
|
||||
struct rtnl_cls *tc_classifier; // libnl3: Firewall mark classifier
|
||||
#endif // WITH_NETEM
|
||||
#endif // __linux__
|
||||
struct rtnl_qdisc *tc_qdisc; // libnl3: Network emulator queuing discipline
|
||||
struct rtnl_cls *tc_classifier; // libnl3: Firewall mark classifier
|
||||
#endif // WITH_NETEM
|
||||
#endif // __linux__
|
||||
|
||||
protected:
|
||||
enum State state;
|
||||
enum State state;
|
||||
|
||||
uuid_t uuid;
|
||||
uuid_t uuid;
|
||||
|
||||
bool enabled;
|
||||
bool enabled;
|
||||
|
||||
Stats::Ptr stats; // Statistic counters. This is a pointer to the statistic hooks private data.
|
||||
Stats::Ptr
|
||||
stats; // Statistic counters. This is a pointer to the statistic hooks private data.
|
||||
|
||||
json_t *config; // A JSON object containing the configuration of the node.
|
||||
json_t *config; // A JSON object containing the configuration of the node.
|
||||
|
||||
std::string name_short; // A short identifier of the node, only used for configuration and logging
|
||||
std::string name_long; // Singleton: A string used to print to screen.
|
||||
std::string name_full; // Singleton: A string used to print to screen.
|
||||
std::string details;
|
||||
std::string
|
||||
name_short; // A short identifier of the node, only used for configuration and logging
|
||||
std::string name_long; // Singleton: A string used to print to screen.
|
||||
std::string name_full; // Singleton: A string used to print to screen.
|
||||
std::string details;
|
||||
|
||||
int affinity; // CPU Affinity of this node
|
||||
int affinity; // CPU Affinity of this node
|
||||
|
||||
NodeFactory *factory; // The factory which created this instance
|
||||
NodeFactory *factory; // The factory which created this instance
|
||||
|
||||
virtual
|
||||
int _read(struct Sample * smps[], unsigned cnt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt) { return -1; }
|
||||
|
||||
virtual
|
||||
int _write(struct Sample * smps[], unsigned cnt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt) { return -1; }
|
||||
|
||||
virtual
|
||||
json_t * _readStatus() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual json_t *_readStatus() const { return nullptr; }
|
||||
|
||||
public:
|
||||
// Initialize node with default values
|
||||
Node(const uuid_t &id = {}, const std::string &name = "");
|
||||
// Initialize node with default values
|
||||
Node(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
// Destroy node by freeing dynamically allocated memory.
|
||||
virtual
|
||||
~Node();
|
||||
// Destroy node by freeing dynamically allocated memory.
|
||||
virtual ~Node();
|
||||
|
||||
// Do initialization after parsing the configuration
|
||||
virtual
|
||||
int prepare();
|
||||
// Do initialization after parsing the configuration
|
||||
virtual int prepare();
|
||||
|
||||
/* Parse settings of a node.
|
||||
/* Parse settings of a node.
|
||||
*
|
||||
* @param json A JSON object containing the configuration of the node.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
// Validate node configuration.
|
||||
virtual
|
||||
int check();
|
||||
// Validate node configuration.
|
||||
virtual int check();
|
||||
|
||||
// Start operation of a node.
|
||||
virtual
|
||||
int start();
|
||||
// Start operation of a node.
|
||||
virtual int start();
|
||||
|
||||
// Stops operation of a node.
|
||||
virtual
|
||||
int stop();
|
||||
// Stops operation of a node.
|
||||
virtual int stop();
|
||||
|
||||
// Pauses operation of a node.
|
||||
virtual
|
||||
int pause()
|
||||
{
|
||||
if (state != State::STARTED)
|
||||
return -1;
|
||||
// Pauses operation of a node.
|
||||
virtual int pause() {
|
||||
if (state != State::STARTED)
|
||||
return -1;
|
||||
|
||||
logger->info("Pausing node");
|
||||
logger->info("Pausing node");
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Resumes operation of a node.
|
||||
virtual
|
||||
int resume()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// Resumes operation of a node.
|
||||
virtual int resume() { return 0; }
|
||||
|
||||
// Restarts operation of a node.
|
||||
virtual
|
||||
int restart();
|
||||
// Restarts operation of a node.
|
||||
virtual int restart();
|
||||
|
||||
/* Receive multiple messages at once.
|
||||
/* Receive multiple messages at once.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -181,9 +160,9 @@ public:
|
|||
* @param cnt The number of samples that are allocated by the calling function.
|
||||
* @return The number of messages actually received.
|
||||
*/
|
||||
int read(struct Sample * smps[], unsigned cnt);
|
||||
int read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
/* Send multiple messages in a single datagram / packet.
|
||||
/* Send multiple messages in a single datagram / packet.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -196,290 +175,193 @@ public:
|
|||
* @param cnt The number of samples that are allocated by the calling function.
|
||||
* @return The number of messages actually sent.
|
||||
*/
|
||||
int write(struct Sample * smps[], unsigned cnt);
|
||||
int write(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
// Reverse local and remote socket address.
|
||||
virtual
|
||||
int reverse()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// Reverse local and remote socket address.
|
||||
virtual int reverse() { return -1; }
|
||||
|
||||
/* Get a list of file descriptors on which the path should poll
|
||||
/* Get a list of file descriptors on which the path should poll
|
||||
* to detect the availability of new samples which can be read.
|
||||
*/
|
||||
virtual
|
||||
std::vector<int> getPollFDs()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
virtual std::vector<int> getPollFDs() { return {}; }
|
||||
|
||||
/* Get a list of socket file descriptors which are used by the node
|
||||
/* Get a list of socket file descriptors which are used by the node
|
||||
* To perform network IO. We use those to selectively apply network emulation
|
||||
*/
|
||||
virtual
|
||||
std::vector<int> getNetemFDs()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
virtual std::vector<int> getNetemFDs() { return {}; }
|
||||
|
||||
/* Get the memory type which this node-type expects.
|
||||
/* Get the memory type which this node-type expects.
|
||||
*
|
||||
* This is useful for special node-types like Infiniband, GPUs & FPGAs
|
||||
* which require DMA-backed memory.
|
||||
*/
|
||||
virtual
|
||||
struct villas::node::memory::Type * getMemoryType()
|
||||
{
|
||||
return villas::node::memory::default_type;
|
||||
}
|
||||
virtual struct villas::node::memory::Type *getMemoryType() {
|
||||
return villas::node::memory::default_type;
|
||||
}
|
||||
|
||||
// Get the factory which was used to construct this node.
|
||||
villas::node::NodeFactory * getFactory() const
|
||||
{
|
||||
return factory;
|
||||
}
|
||||
// Get the factory which was used to construct this node.
|
||||
villas::node::NodeFactory *getFactory() const { return factory; }
|
||||
|
||||
/* Return a pointer to a string which should be used to print this node.
|
||||
/* Return a pointer to a string which should be used to print this node.
|
||||
*
|
||||
* @param n A pointer to the node structure.
|
||||
*/
|
||||
std::string getNameShort() const
|
||||
{
|
||||
return name_short;
|
||||
}
|
||||
std::string getNameShort() const { return name_short; }
|
||||
|
||||
// Return a pointer to a string which should be used to print this node.
|
||||
const std::string & getName() const
|
||||
{
|
||||
return name_long;
|
||||
}
|
||||
// Return a pointer to a string which should be used to print this node.
|
||||
const std::string &getName() const { return name_long; }
|
||||
|
||||
// Get the full name including type and details of the node.
|
||||
const std::string & getNameFull();
|
||||
// Get the full name including type and details of the node.
|
||||
const std::string &getNameFull();
|
||||
|
||||
// Just get the config details of this node as a string
|
||||
virtual
|
||||
const std::string & getDetails()
|
||||
{
|
||||
static
|
||||
std::string empty;
|
||||
// Just get the config details of this node as a string
|
||||
virtual const std::string &getDetails() {
|
||||
static std::string empty;
|
||||
|
||||
return empty;
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
|
||||
/* Return a pointer to a string which should be used to print this node.
|
||||
/* Return a pointer to a string which should be used to print this node.
|
||||
*
|
||||
* @param n A pointer to the node structure.
|
||||
*/
|
||||
const std::string & getNameLong();
|
||||
const std::string &getNameLong();
|
||||
|
||||
/* Return a list of signals which are sent to this node.
|
||||
/* Return a list of signals which are sent to this node.
|
||||
*
|
||||
* This list is derived from the path which uses the node as destination.
|
||||
*/
|
||||
SignalList::Ptr getOutputSignals(bool after_hooks = true) const;
|
||||
SignalList::Ptr getInputSignals(bool after_hooks = true) const;
|
||||
SignalList::Ptr getOutputSignals(bool after_hooks = true) const;
|
||||
SignalList::Ptr getInputSignals(bool after_hooks = true) const;
|
||||
|
||||
// Get the number of input signals (received by this node)
|
||||
unsigned getInputSignalsMaxCount() const;
|
||||
// Get the number of input signals (received by this node)
|
||||
unsigned getInputSignalsMaxCount() const;
|
||||
|
||||
// Get the number of output signals (send out via this node)
|
||||
unsigned getOutputSignalsMaxCount() const;
|
||||
// Get the number of output signals (send out via this node)
|
||||
unsigned getOutputSignalsMaxCount() const;
|
||||
|
||||
void swapSignals();
|
||||
void swapSignals();
|
||||
|
||||
// Get the node configuration as JSON.
|
||||
json_t * getConfig()
|
||||
{
|
||||
return config;
|
||||
}
|
||||
// Get the node configuration as JSON.
|
||||
json_t *getConfig() { return config; }
|
||||
|
||||
// Get the state of this node.
|
||||
enum State getState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
// Get the state of this node.
|
||||
enum State getState() const { return state; }
|
||||
|
||||
// Set the state of this node.
|
||||
void setState(enum State s)
|
||||
{
|
||||
state = s;
|
||||
}
|
||||
// Set the state of this node.
|
||||
void setState(enum State s) { state = s; }
|
||||
|
||||
// Get the UUID of this node.
|
||||
const uuid_t & getUuid() const
|
||||
{
|
||||
return uuid;
|
||||
}
|
||||
// Get the UUID of this node.
|
||||
const uuid_t &getUuid() const { return uuid; }
|
||||
|
||||
std::shared_ptr<Stats> getStats()
|
||||
{
|
||||
return stats;
|
||||
}
|
||||
std::shared_ptr<Stats> getStats() { return stats; }
|
||||
|
||||
void setStats(std::shared_ptr<Stats> sts)
|
||||
{
|
||||
stats = sts;
|
||||
}
|
||||
void setStats(std::shared_ptr<Stats> sts) { stats = sts; }
|
||||
|
||||
void setEnabled(bool en)
|
||||
{
|
||||
enabled = en;
|
||||
}
|
||||
void setEnabled(bool en) { enabled = en; }
|
||||
|
||||
// Custom formatter for spdlog
|
||||
template<typename OStream>
|
||||
friend OStream &operator<<(OStream &os, const Node &n)
|
||||
{
|
||||
os << n.getName();
|
||||
// Custom formatter for spdlog
|
||||
template <typename OStream>
|
||||
friend OStream &operator<<(OStream &os, const Node &n) {
|
||||
os << n.getName();
|
||||
|
||||
return os;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
json_t * toJson() const;
|
||||
json_t *toJson() const;
|
||||
|
||||
static
|
||||
bool isValidName(const std::string &name);
|
||||
static bool isValidName(const std::string &name);
|
||||
|
||||
bool isEnabled() const
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
bool isEnabled() const { return enabled; }
|
||||
};
|
||||
|
||||
class NodeFactory : public villas::plugin::Plugin {
|
||||
|
||||
friend Node;
|
||||
friend Node;
|
||||
|
||||
protected:
|
||||
virtual
|
||||
void init(Node *n)
|
||||
{
|
||||
n->logger = getLogger();
|
||||
n->factory = this;
|
||||
virtual void init(Node *n) {
|
||||
n->logger = getLogger();
|
||||
n->factory = this;
|
||||
|
||||
n->name_long = fmt::format(CLR_RED("{}") "(" CLR_YEL("{}") ")", n->name_short, getName());
|
||||
n->name_long = fmt::format(CLR_RED("{}") "(" CLR_YEL("{}") ")",
|
||||
n->name_short, getName());
|
||||
|
||||
instances.push_back(n);
|
||||
}
|
||||
instances.push_back(n);
|
||||
}
|
||||
|
||||
State state;
|
||||
State state;
|
||||
|
||||
public:
|
||||
enum class Flags {
|
||||
SUPPORTS_POLL = (1 << 0),
|
||||
SUPPORTS_READ = (1 << 1),
|
||||
SUPPORTS_WRITE = (1 << 2),
|
||||
REQUIRES_WEB = (1 << 3),
|
||||
PROVIDES_SIGNALS = (1 << 4),
|
||||
INTERNAL = (1 << 5),
|
||||
HIDDEN = (1 << 6)
|
||||
};
|
||||
enum class Flags {
|
||||
SUPPORTS_POLL = (1 << 0),
|
||||
SUPPORTS_READ = (1 << 1),
|
||||
SUPPORTS_WRITE = (1 << 2),
|
||||
REQUIRES_WEB = (1 << 3),
|
||||
PROVIDES_SIGNALS = (1 << 4),
|
||||
INTERNAL = (1 << 5),
|
||||
HIDDEN = (1 << 6)
|
||||
};
|
||||
|
||||
NodeList instances;
|
||||
NodeList instances;
|
||||
|
||||
NodeFactory() :
|
||||
Plugin()
|
||||
{
|
||||
state = State::INITIALIZED;
|
||||
}
|
||||
NodeFactory() : Plugin() { state = State::INITIALIZED; }
|
||||
|
||||
virtual
|
||||
Node * make(const uuid_t &id = {}, const std::string &nme = "") = 0;
|
||||
virtual Node *make(const uuid_t &id = {}, const std::string &nme = "") = 0;
|
||||
|
||||
static
|
||||
Node * make(json_t *json, const uuid_t &id, const std::string &name = "");
|
||||
static Node *make(json_t *json, const uuid_t &id,
|
||||
const std::string &name = "");
|
||||
|
||||
static
|
||||
Node * make(const std::string &type, const uuid_t &id = {}, const std::string &name = "");
|
||||
static Node *make(const std::string &type, const uuid_t &id = {},
|
||||
const std::string &name = "");
|
||||
|
||||
virtual
|
||||
std::string getType() const
|
||||
{
|
||||
return "node";
|
||||
}
|
||||
virtual std::string getType() const { return "node"; }
|
||||
|
||||
// Custom formatter for spdlog
|
||||
template<typename OStream>
|
||||
friend OStream &operator<<(OStream &os, const NodeFactory &f)
|
||||
{
|
||||
os << f.getName();
|
||||
// Custom formatter for spdlog
|
||||
template <typename OStream>
|
||||
friend OStream &operator<<(OStream &os, const NodeFactory &f) {
|
||||
os << f.getName();
|
||||
|
||||
return os;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
virtual
|
||||
int getFlags() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int getFlags() const { return 0; }
|
||||
|
||||
virtual
|
||||
int getVectorize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int getVectorize() const { return 0; }
|
||||
|
||||
bool isInternal() const
|
||||
{
|
||||
return getFlags() & (int) Flags::INTERNAL;
|
||||
}
|
||||
bool isInternal() const { return getFlags() & (int)Flags::INTERNAL; }
|
||||
|
||||
bool isHidden() const
|
||||
{
|
||||
return isInternal() || getFlags() & (int) Flags::HIDDEN;
|
||||
}
|
||||
bool isHidden() const {
|
||||
return isInternal() || getFlags() & (int)Flags::HIDDEN;
|
||||
}
|
||||
|
||||
virtual
|
||||
int start(SuperNode *sn);
|
||||
virtual int start(SuperNode *sn);
|
||||
|
||||
virtual
|
||||
int stop();
|
||||
virtual int stop();
|
||||
|
||||
State getState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
State getState() const { return state; }
|
||||
};
|
||||
|
||||
template<typename T, const char *name, const char *desc, int flags = 0, int vectorize = 0>
|
||||
template <typename T, const char *name, const char *desc, int flags = 0,
|
||||
int vectorize = 0>
|
||||
class NodePlugin : public NodeFactory {
|
||||
|
||||
public:
|
||||
virtual
|
||||
Node * make(const uuid_t &id = {}, const std::string &nme = "")
|
||||
{
|
||||
T* n = new T(id, nme);
|
||||
virtual Node *make(const uuid_t &id = {}, const std::string &nme = "") {
|
||||
T *n = new T(id, nme);
|
||||
|
||||
init(n);
|
||||
init(n);
|
||||
|
||||
return n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
virtual
|
||||
int getFlags() const
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
virtual int getFlags() const { return flags; }
|
||||
|
||||
virtual
|
||||
int getVectorize() const
|
||||
{
|
||||
return vectorize;
|
||||
}
|
||||
virtual int getVectorize() const { return vectorize; }
|
||||
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
virtual std::string getName() const { return name; }
|
||||
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
virtual std::string getDescription() const { return desc; }
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/exceptions.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
|
||||
#ifdef WITH_CONFIG
|
||||
#include <libconfig.h>
|
||||
#include <libconfig.h>
|
||||
#endif
|
||||
|
||||
namespace villas {
|
||||
|
@ -20,54 +20,40 @@ namespace node {
|
|||
class ParseError : public RuntimeError {
|
||||
|
||||
protected:
|
||||
std::string text;
|
||||
std::string file;
|
||||
int line;
|
||||
int column;
|
||||
std::string text;
|
||||
std::string file;
|
||||
int line;
|
||||
int column;
|
||||
|
||||
public:
|
||||
ParseError(const std::string &t, const std::string &f, int l, int c = 0) :
|
||||
RuntimeError("Failed to parse configuration: {} in {}:{}", t, f, l),
|
||||
text(t),
|
||||
file(f),
|
||||
line(l),
|
||||
column(c)
|
||||
{ }
|
||||
ParseError(const std::string &t, const std::string &f, int l, int c = 0)
|
||||
: RuntimeError("Failed to parse configuration: {} in {}:{}", t, f, l),
|
||||
text(t), file(f), line(l), column(c) {}
|
||||
};
|
||||
|
||||
#ifdef WITH_CONFIG
|
||||
class LibconfigParseError : public ParseError {
|
||||
|
||||
protected:
|
||||
const config_t *config;
|
||||
const config_t *config;
|
||||
|
||||
public:
|
||||
LibconfigParseError(const config_t *c) :
|
||||
ParseError(
|
||||
config_error_text(c),
|
||||
config_error_file(c) ? config_error_file(c) : "<unknown>",
|
||||
config_error_line(c)
|
||||
),
|
||||
config(c)
|
||||
{ }
|
||||
LibconfigParseError(const config_t *c)
|
||||
: ParseError(config_error_text(c),
|
||||
config_error_file(c) ? config_error_file(c) : "<unknown>",
|
||||
config_error_line(c)),
|
||||
config(c) {}
|
||||
};
|
||||
#endif // WITH_CONFIG
|
||||
|
||||
class JanssonParseError : public ParseError {
|
||||
|
||||
protected:
|
||||
json_error_t error;
|
||||
json_error_t error;
|
||||
|
||||
public:
|
||||
JanssonParseError(json_error_t e) :
|
||||
ParseError(
|
||||
e.text,
|
||||
e.source,
|
||||
e.line,
|
||||
e.column
|
||||
),
|
||||
error(e)
|
||||
{ }
|
||||
JanssonParseError(json_error_t e)
|
||||
: ParseError(e.text, e.source, e.line, e.column), error(e) {}
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef IBVERBS_FOUND
|
||||
#include <infiniband/verbs.h>
|
||||
#include <infiniband/verbs.h>
|
||||
#endif // IBVERBS_FOUND
|
||||
|
||||
#include <cstddef>
|
||||
|
@ -24,36 +24,36 @@ namespace memory {
|
|||
/* Descriptor of a memory block. Associated block always starts at
|
||||
* &m + sizeof(struct Block). */
|
||||
struct Block {
|
||||
struct Block *prev;
|
||||
struct Block *next;
|
||||
size_t length; // Length of the block; doesn't include the descriptor itself
|
||||
bool used;
|
||||
struct Block *prev;
|
||||
struct Block *next;
|
||||
size_t length; // Length of the block; doesn't include the descriptor itself
|
||||
bool used;
|
||||
};
|
||||
|
||||
// TODO: Unused for now
|
||||
struct Allocation {
|
||||
struct Type *type;
|
||||
struct Type *type;
|
||||
|
||||
struct Allocation *parent;
|
||||
struct Allocation *parent;
|
||||
|
||||
void *address;
|
||||
size_t alignment;
|
||||
size_t length;
|
||||
void *address;
|
||||
size_t alignment;
|
||||
size_t length;
|
||||
|
||||
union {
|
||||
union {
|
||||
#ifdef IBVERBS_FOUND
|
||||
struct {
|
||||
struct ibv_mr *mr;
|
||||
} ib;
|
||||
struct {
|
||||
struct ibv_mr *mr;
|
||||
} ib;
|
||||
#endif
|
||||
struct {
|
||||
struct Block *block;
|
||||
} managed;
|
||||
};
|
||||
struct {
|
||||
struct Block *block;
|
||||
} managed;
|
||||
};
|
||||
};
|
||||
|
||||
// Initilialize memory subsystem
|
||||
int init(int hugepages) __attribute__ ((warn_unused_result));
|
||||
int init(int hugepages) __attribute__((warn_unused_result));
|
||||
|
||||
int lock(size_t lock);
|
||||
|
||||
|
@ -62,13 +62,14 @@ int lock(size_t lock);
|
|||
* @retval nullptr If allocation failed.
|
||||
* @retval <>0 If allocation was successful.
|
||||
*/
|
||||
void * alloc(size_t len, struct Type *m = default_type);
|
||||
void *alloc(size_t len, struct Type *m = default_type);
|
||||
|
||||
void * alloc_aligned(size_t len, size_t alignment, struct Type *m = default_type);
|
||||
void *alloc_aligned(size_t len, size_t alignment,
|
||||
struct Type *m = default_type);
|
||||
|
||||
int free(void *ptr);
|
||||
|
||||
struct Allocation * get_allocation(void *ptr);
|
||||
struct Allocation *get_allocation(void *ptr);
|
||||
|
||||
} // namespace memory
|
||||
} // namespace node
|
||||
|
|
|
@ -20,41 +20,38 @@ namespace memory {
|
|||
|
||||
struct Type;
|
||||
|
||||
typedef struct Allocation * (*allocator_t)(size_t len, size_t alignment, struct Type *mem);
|
||||
typedef int (*deallocator_t)(struct Allocation * ma, struct Type *mem);
|
||||
typedef struct Allocation *(*allocator_t)(size_t len, size_t alignment,
|
||||
struct Type *mem);
|
||||
typedef int (*deallocator_t)(struct Allocation *ma, struct Type *mem);
|
||||
|
||||
enum class Flags {
|
||||
MMAP = (1 << 0),
|
||||
DMA = (1 << 1),
|
||||
HUGEPAGE = (1 << 2),
|
||||
HEAP = (1 << 3)
|
||||
MMAP = (1 << 0),
|
||||
DMA = (1 << 1),
|
||||
HUGEPAGE = (1 << 2),
|
||||
HEAP = (1 << 3)
|
||||
};
|
||||
|
||||
struct Type {
|
||||
const char *name;
|
||||
int flags;
|
||||
const char *name;
|
||||
int flags;
|
||||
|
||||
size_t alignment;
|
||||
size_t alignment;
|
||||
|
||||
allocator_t alloc;
|
||||
deallocator_t free;
|
||||
allocator_t alloc;
|
||||
deallocator_t free;
|
||||
|
||||
void *_vd; // Virtual data for internal state
|
||||
void *_vd; // Virtual data for internal state
|
||||
};
|
||||
|
||||
extern
|
||||
struct Type heap;
|
||||
extern
|
||||
struct Type mmap;
|
||||
extern
|
||||
struct Type mmap_hugetlb;
|
||||
extern
|
||||
struct Type *default_type;
|
||||
extern struct Type heap;
|
||||
extern struct Type mmap;
|
||||
extern struct Type mmap_hugetlb;
|
||||
extern struct Type *default_type;
|
||||
|
||||
struct Type * ib(NodeCompat *n, struct Type *parent);
|
||||
struct Type * managed(void *ptr, size_t len);
|
||||
struct Type *ib(NodeCompat *n, struct Type *parent);
|
||||
struct Type *managed(void *ptr, size_t len);
|
||||
|
||||
int mmap_init(int hugepages) __attribute__ ((warn_unused_result));
|
||||
int mmap_init(int hugepages) __attribute__((warn_unused_result));
|
||||
|
||||
} // namespace memory
|
||||
} // namespace node
|
||||
|
|
|
@ -5,14 +5,13 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
#include <villas/sample.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/node_compat_type.hpp>
|
||||
#include <villas/sample.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -23,174 +22,132 @@ class NodeCompatFactory;
|
|||
class NodeCompat : public Node {
|
||||
|
||||
protected:
|
||||
struct NodeCompatType *_vt; // Virtual functions (C++ OOP style)
|
||||
void *_vd; // Virtual data (used by struct vnode::_vt functions)
|
||||
struct NodeCompatType *_vt; // Virtual functions (C++ OOP style)
|
||||
void *_vd; // Virtual data (used by struct vnode::_vt functions)
|
||||
|
||||
std::string _details;
|
||||
std::string _details;
|
||||
|
||||
virtual
|
||||
int _read(struct Sample *smps[], unsigned cnt);
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int _write(struct Sample *smps[], unsigned cnt);
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
NodeCompat *node;
|
||||
json_t *cfg;
|
||||
NodeCompat *node;
|
||||
json_t *cfg;
|
||||
|
||||
NodeCompat(struct NodeCompatType *vt, const uuid_t &id, const std::string &name);
|
||||
NodeCompat(const NodeCompat& n);
|
||||
NodeCompat(struct NodeCompatType *vt, const uuid_t &id,
|
||||
const std::string &name);
|
||||
NodeCompat(const NodeCompat &n);
|
||||
|
||||
NodeCompat& operator=(const NodeCompat& other);
|
||||
NodeCompat &operator=(const NodeCompat &other);
|
||||
|
||||
virtual
|
||||
~NodeCompat();
|
||||
virtual ~NodeCompat();
|
||||
|
||||
template<typename T>
|
||||
T * getData()
|
||||
{
|
||||
return static_cast<T *>(_vd);
|
||||
}
|
||||
template <typename T> T *getData() { return static_cast<T *>(_vd); }
|
||||
|
||||
virtual
|
||||
NodeCompatType * getType() const
|
||||
{
|
||||
return _vt;
|
||||
}
|
||||
virtual NodeCompatType *getType() const { return _vt; }
|
||||
|
||||
/* Parse node connection details.
|
||||
/* Parse node connection details.
|
||||
|
||||
*
|
||||
* @param json A JSON object containing the configuration of the node.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
// Returns a string with a textual represenation of this node.
|
||||
virtual
|
||||
const std::string & getDetails();
|
||||
// Returns a string with a textual represenation of this node.
|
||||
virtual const std::string &getDetails();
|
||||
|
||||
/* Check the current node configuration for plausability and errors.
|
||||
/* Check the current node configuration for plausability and errors.
|
||||
|
||||
*
|
||||
* @retval 0 Success. Node configuration is good.
|
||||
* @retval <0 Error. The node configuration is bogus.
|
||||
*/
|
||||
virtual
|
||||
int check();
|
||||
virtual int check();
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
virtual int prepare();
|
||||
|
||||
/* Start this node.
|
||||
/* Start this node.
|
||||
|
||||
*
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
virtual
|
||||
int start();
|
||||
virtual int start();
|
||||
|
||||
/* Stop this node.
|
||||
/* Stop this node.
|
||||
|
||||
*
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
virtual
|
||||
int stop();
|
||||
virtual int stop();
|
||||
|
||||
/* Restart this node.
|
||||
/* Restart this node.
|
||||
|
||||
*
|
||||
* @param n A pointer to the node object.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
virtual
|
||||
int restart();
|
||||
virtual int restart();
|
||||
|
||||
/* Pause this node.
|
||||
/* Pause this node.
|
||||
|
||||
*
|
||||
* @param n A pointer to the node object.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
virtual
|
||||
int pause();
|
||||
virtual int pause();
|
||||
|
||||
/* Resume this node.
|
||||
/* Resume this node.
|
||||
|
||||
*
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
virtual
|
||||
int resume();
|
||||
virtual int resume();
|
||||
|
||||
/* Reverse source and destination of a node.
|
||||
/* Reverse source and destination of a node.
|
||||
|
||||
*/
|
||||
virtual
|
||||
int reverse();
|
||||
virtual int reverse();
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs();
|
||||
virtual std::vector<int> getPollFDs();
|
||||
|
||||
// Get list of socket file descriptors for configuring network emulation.
|
||||
virtual
|
||||
std::vector<int> getNetemFDs();
|
||||
// Get list of socket file descriptors for configuring network emulation.
|
||||
virtual std::vector<int> getNetemFDs();
|
||||
|
||||
// Return a memory allocator which should be used for sample pools passed to this node.
|
||||
virtual
|
||||
struct memory::Type * getMemoryType();
|
||||
// Return a memory allocator which should be used for sample pools passed to this node.
|
||||
virtual struct memory::Type *getMemoryType();
|
||||
};
|
||||
|
||||
class NodeCompatFactory : public NodeFactory {
|
||||
|
||||
protected:
|
||||
struct NodeCompatType *_vt;
|
||||
struct NodeCompatType *_vt;
|
||||
|
||||
public:
|
||||
NodeCompatFactory(struct NodeCompatType *vt) :
|
||||
NodeFactory(),
|
||||
_vt(vt)
|
||||
{ }
|
||||
NodeCompatFactory(struct NodeCompatType *vt) : NodeFactory(), _vt(vt) {}
|
||||
|
||||
virtual
|
||||
Node * make(const uuid_t &id = {}, const std::string &name = "");
|
||||
virtual Node *make(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
/// Get plugin name
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return _vt->name;
|
||||
}
|
||||
/// Get plugin name
|
||||
virtual std::string getName() const { return _vt->name; }
|
||||
|
||||
/// Get plugin description
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return _vt->description;
|
||||
}
|
||||
/// Get plugin description
|
||||
virtual std::string getDescription() const { return _vt->description; }
|
||||
|
||||
virtual
|
||||
int getFlags() const;
|
||||
virtual int getFlags() const;
|
||||
|
||||
virtual
|
||||
int getVectorize() const
|
||||
{
|
||||
return _vt->vectorize;
|
||||
}
|
||||
virtual int getVectorize() const { return _vt->vectorize; }
|
||||
|
||||
virtual
|
||||
int start(SuperNode *sn);
|
||||
virtual int start(SuperNode *sn);
|
||||
|
||||
virtual
|
||||
int stop();
|
||||
virtual int stop();
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#include <spdlog/fmt/ostr.h>
|
||||
|
||||
#include <villas/common.hpp>
|
||||
#include <villas/node/memory.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/node/memory.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -25,18 +25,19 @@ class SuperNode;
|
|||
class NodeCompatType {
|
||||
|
||||
public:
|
||||
const char *name;
|
||||
const char *description;
|
||||
const char *name;
|
||||
const char *description;
|
||||
|
||||
unsigned vectorize; // Maximal vector length supported by this node type. Zero is unlimited.
|
||||
int flags;
|
||||
unsigned
|
||||
vectorize; // Maximal vector length supported by this node type. Zero is unlimited.
|
||||
int flags;
|
||||
|
||||
enum State state; // State of this node-type.
|
||||
enum State state; // State of this node-type.
|
||||
|
||||
size_t size; // Size of private data bock. @see node::_vd
|
||||
size_t size; // Size of private data bock. @see node::_vd
|
||||
|
||||
struct {
|
||||
/* Global initialization per node type.
|
||||
struct {
|
||||
/* Global initialization per node type.
|
||||
*
|
||||
* This callback is invoked once per node-type.
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
|
@ -44,9 +45,9 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*start)(SuperNode *sn);
|
||||
int (*start)(SuperNode *sn);
|
||||
|
||||
/* Global de-initialization per node type.
|
||||
/* Global de-initialization per node type.
|
||||
*
|
||||
* This callback is invoked once per node-type.
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
|
@ -54,27 +55,27 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*stop)();
|
||||
} type;
|
||||
int (*stop)();
|
||||
} type;
|
||||
|
||||
/* Initialize a new node instance.
|
||||
/* Initialize a new node instance.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*init)(NodeCompat *n);
|
||||
int (*init)(NodeCompat *n);
|
||||
|
||||
/* Free memory of an instance of this type.
|
||||
/* Free memory of an instance of this type.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
* @param n A pointer to the node object.
|
||||
*/
|
||||
int (*destroy)(NodeCompat *n);
|
||||
int (*destroy)(NodeCompat *n);
|
||||
|
||||
/* Parse node connection details.
|
||||
/* Parse node connection details.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -83,9 +84,9 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*parse)(NodeCompat *n, json_t *json);
|
||||
int (*parse)(NodeCompat *n, json_t *json);
|
||||
|
||||
/* Check the current node configuration for plausability and errors.
|
||||
/* Check the current node configuration for plausability and errors.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -93,20 +94,20 @@ public:
|
|||
* @retval 0 Success. Node configuration is good.
|
||||
* @retval <0 Error. The node configuration is bogus.
|
||||
*/
|
||||
int (*check)(NodeCompat *n);
|
||||
int (*check)(NodeCompat *n);
|
||||
|
||||
int (*prepare)(NodeCompat *n);
|
||||
int (*prepare)(NodeCompat *n);
|
||||
|
||||
/* Returns a string with a textual represenation of this node.
|
||||
/* Returns a string with a textual represenation of this node.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
* @param n A pointer to the node object.
|
||||
* @return A pointer to a dynamically allocated string. Must be freed().
|
||||
*/
|
||||
char * (*print)(NodeCompat *n);
|
||||
char *(*print)(NodeCompat *n);
|
||||
|
||||
/* Start this node.
|
||||
/* Start this node.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -114,9 +115,9 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*start)(NodeCompat *n);
|
||||
int (*start)(NodeCompat *n);
|
||||
|
||||
/* Restart this node.
|
||||
/* Restart this node.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -124,9 +125,9 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*restart)(NodeCompat *n);
|
||||
int (*restart)(NodeCompat *n);
|
||||
|
||||
/* Stop this node.
|
||||
/* Stop this node.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -134,9 +135,9 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*stop)(NodeCompat *n);
|
||||
int (*stop)(NodeCompat *n);
|
||||
|
||||
/* Pause this node.
|
||||
/* Pause this node.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -144,9 +145,9 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*pause)(NodeCompat *n);
|
||||
int (*pause)(NodeCompat *n);
|
||||
|
||||
/* Resume this node.
|
||||
/* Resume this node.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -154,9 +155,9 @@ public:
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*resume)(NodeCompat *n);
|
||||
int (*resume)(NodeCompat *n);
|
||||
|
||||
/* Receive multiple messages at once.
|
||||
/* Receive multiple messages at once.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -172,9 +173,9 @@ public:
|
|||
* @param release The number of samples that should be released after read is called.
|
||||
* @return The number of messages actually received.
|
||||
*/
|
||||
int (*read)(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int (*read)(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
/* Send multiple messages in a single datagram / packet.
|
||||
/* Send multiple messages in a single datagram / packet.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
|
@ -189,34 +190,35 @@ public:
|
|||
* @param release The number of samples that should be released after write is called
|
||||
* @return The number of messages actually sent.
|
||||
*/
|
||||
int (*write)(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int (*write)(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
/* Reverse source and destination of a node.
|
||||
/* Reverse source and destination of a node.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
* @param n A pointer to the node object.
|
||||
*/
|
||||
int (*reverse)(NodeCompat *n);
|
||||
int (*reverse)(NodeCompat *n);
|
||||
|
||||
/* Get list of file descriptors which can be used by poll/select to detect the availability of new data.
|
||||
/* Get list of file descriptors which can be used by poll/select to detect the availability of new data.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
* @return The number of file descriptors which have been put into \p fds.
|
||||
*/
|
||||
int (*poll_fds)(NodeCompat *n, int fds[]);
|
||||
int (*poll_fds)(NodeCompat *n, int fds[]);
|
||||
|
||||
/* Get list of socket file descriptors for configuring network emulation.
|
||||
/* Get list of socket file descriptors for configuring network emulation.
|
||||
*
|
||||
* This callback is optional. It will only be called if non-null.
|
||||
*
|
||||
* @return The number of file descriptors which have been put into \p sds.
|
||||
*/
|
||||
int (*netem_fds)(NodeCompat *n, int sds[]);
|
||||
int (*netem_fds)(NodeCompat *n, int sds[]);
|
||||
|
||||
// Return a memory allocator which should be used for sample pools passed to this node.
|
||||
struct memory::Type * (*memory_type)(NodeCompat *n, struct memory::Type *parent);
|
||||
// Return a memory allocator which should be used for sample pools passed to this node.
|
||||
struct memory::Type *(*memory_type)(NodeCompat *n,
|
||||
struct memory::Type *parent);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#include <jansson.h>
|
||||
|
||||
#include <villas/common.hpp>
|
||||
#include <villas/hook_list.hpp>
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/signal_list.hpp>
|
||||
#include <villas/hook_list.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -22,42 +22,43 @@ class Node;
|
|||
class Path;
|
||||
|
||||
class NodeDirection {
|
||||
friend Node;
|
||||
friend Node;
|
||||
|
||||
public:
|
||||
enum class Direction {
|
||||
IN, // VILLASnode is receiving/reading
|
||||
OUT // VILLASnode is sending/writing
|
||||
} direction;
|
||||
enum class Direction {
|
||||
IN, // VILLASnode is receiving/reading
|
||||
OUT // VILLASnode is sending/writing
|
||||
} direction;
|
||||
|
||||
/* The path which uses this node as a source/destination.
|
||||
/* 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.
|
||||
*/
|
||||
Path *path;
|
||||
Node *node;
|
||||
Path *path;
|
||||
Node *node;
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
HookList hooks; // List of read / write hooks (struct hook).
|
||||
SignalList::Ptr signals; // Signal description.
|
||||
HookList hooks; // List of read / write hooks (struct hook).
|
||||
SignalList::Ptr signals; // Signal description.
|
||||
|
||||
json_t *config; // A JSON object containing the configuration of the node.
|
||||
json_t *config; // A JSON object containing the configuration of the node.
|
||||
|
||||
NodeDirection(enum NodeDirection::Direction dir, Node *n);
|
||||
NodeDirection(enum NodeDirection::Direction dir, Node *n);
|
||||
|
||||
int parse(json_t *json);
|
||||
void check();
|
||||
int prepare();
|
||||
int start();
|
||||
int stop();
|
||||
int parse(json_t *json);
|
||||
void check();
|
||||
int prepare();
|
||||
int start();
|
||||
int stop();
|
||||
|
||||
SignalList::Ptr getSignals(int after_hooks = true) const;
|
||||
SignalList::Ptr getSignals(int after_hooks = true) const;
|
||||
|
||||
unsigned getSignalsMaxCount() const;
|
||||
unsigned getSignalsMaxCount() const;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
#include <jansson.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
@ -22,13 +22,13 @@ class Node;
|
|||
class NodeList : public std::list<Node *> {
|
||||
|
||||
public:
|
||||
// Lookup a node from the list based on its name
|
||||
Node * lookup(const std::string &name);
|
||||
// Lookup a node from the list based on its name
|
||||
Node *lookup(const std::string &name);
|
||||
|
||||
// Lookup a node from the list based on its UUID
|
||||
Node * lookup(const uuid_t &uuid);
|
||||
// Lookup a node from the list based on its UUID
|
||||
Node *lookup(const uuid_t &uuid);
|
||||
|
||||
/* Parse an array or single node and checks if they exist in the "nodes" section.
|
||||
/* Parse an array or single node and checks if they exist in the "nodes" section.
|
||||
*
|
||||
* Examples:
|
||||
* out = [ "sintef", "scedu" ]
|
||||
|
@ -38,9 +38,9 @@ public:
|
|||
* @param nodes The nodes will be added to this list.
|
||||
* @param all This list contains all valid nodes.
|
||||
*/
|
||||
int parse(json_t *json, NodeList &all);
|
||||
int parse(json_t *json, NodeList &all);
|
||||
|
||||
json_t * toJson() const;
|
||||
json_t *toJson() const;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
#include <amqp.h>
|
||||
#endif
|
||||
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/list.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -25,30 +25,30 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
struct amqp_ssl_info {
|
||||
int verify_peer;
|
||||
int verify_hostname;
|
||||
char *ca_cert;
|
||||
char *client_cert;
|
||||
char *client_key;
|
||||
int verify_peer;
|
||||
int verify_hostname;
|
||||
char *ca_cert;
|
||||
char *client_cert;
|
||||
char *client_key;
|
||||
};
|
||||
|
||||
struct amqp {
|
||||
char *uri;
|
||||
char *uri;
|
||||
|
||||
struct amqp_connection_info connection_info;
|
||||
struct amqp_ssl_info ssl_info;
|
||||
struct amqp_connection_info connection_info;
|
||||
struct amqp_ssl_info ssl_info;
|
||||
|
||||
amqp_bytes_t routing_key;
|
||||
amqp_bytes_t exchange;
|
||||
amqp_bytes_t routing_key;
|
||||
amqp_bytes_t exchange;
|
||||
|
||||
// We need to create two connection because rabbitmq-c is not thread-safe!
|
||||
amqp_connection_state_t producer;
|
||||
amqp_connection_state_t consumer;
|
||||
// We need to create two connection because rabbitmq-c is not thread-safe!
|
||||
amqp_connection_state_t producer;
|
||||
amqp_connection_state_t consumer;
|
||||
|
||||
Format *formatter;
|
||||
Format *formatter;
|
||||
};
|
||||
|
||||
char * amqp_print(NodeCompat *n);
|
||||
char *amqp_print(NodeCompat *n);
|
||||
|
||||
int amqp_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
|
@ -62,9 +62,9 @@ int amqp_poll_fds(NodeCompat *n, int fds[]);
|
|||
|
||||
int amqp_stop(NodeCompat *n);
|
||||
|
||||
int amqp_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int amqp_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int amqp_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int amqp_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/api/universal.hpp>
|
||||
#include <pthread.h>
|
||||
#include <villas/api/universal.hpp>
|
||||
#include <villas/node.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -21,33 +21,28 @@ struct Sample;
|
|||
class APINode : public Node {
|
||||
|
||||
public:
|
||||
APINode(const uuid_t &id = {}, const std::string &name = "");
|
||||
APINode(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
struct Direction {
|
||||
Sample *sample;
|
||||
api::universal::ChannelList channels;
|
||||
pthread_cond_t cv;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
struct Direction {
|
||||
Sample *sample;
|
||||
api::universal::ChannelList channels;
|
||||
pthread_cond_t cv;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
// Accessed by api::universal::SignalRequest
|
||||
Direction read, write;
|
||||
// Accessed by api::universal::SignalRequest
|
||||
Direction read, write;
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
virtual int prepare();
|
||||
|
||||
virtual
|
||||
int check();
|
||||
virtual int check();
|
||||
|
||||
protected:
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
virtual
|
||||
int _read(struct Sample *smps[], unsigned cnt);
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int _write(struct Sample *smps[], unsigned cnt);
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -19,22 +19,22 @@ class NodeCompat;
|
|||
union SignalData;
|
||||
|
||||
struct can_signal {
|
||||
uint32_t id;
|
||||
int offset;
|
||||
int size;
|
||||
uint32_t id;
|
||||
int offset;
|
||||
int size;
|
||||
};
|
||||
|
||||
struct can {
|
||||
// Settings
|
||||
char *interface_name;
|
||||
struct can_signal *in;
|
||||
struct can_signal *out;
|
||||
// Settings
|
||||
char *interface_name;
|
||||
struct can_signal *in;
|
||||
struct can_signal *out;
|
||||
|
||||
// States
|
||||
int socket;
|
||||
union SignalData *sample_buf;
|
||||
size_t sample_buf_num;
|
||||
struct timespec start_time;
|
||||
// States
|
||||
int socket;
|
||||
union SignalData *sample_buf;
|
||||
size_t sample_buf_num;
|
||||
struct timespec start_time;
|
||||
};
|
||||
|
||||
int can_init(NodeCompat *n);
|
||||
|
@ -43,7 +43,7 @@ int can_destroy(NodeCompat *n);
|
|||
|
||||
int can_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
char * can_print(NodeCompat *n);
|
||||
char *can_print(NodeCompat *n);
|
||||
|
||||
int can_check(NodeCompat *n);
|
||||
|
||||
|
@ -53,9 +53,9 @@ int can_start(NodeCompat *n);
|
|||
|
||||
int can_stop(NodeCompat *n);
|
||||
|
||||
int can_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int can_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int can_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int can_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int can_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
|
|
|
@ -23,47 +23,46 @@ class NodeCompat;
|
|||
//#define COMEDI_USE_READ (0)
|
||||
|
||||
struct comedi_chanspec {
|
||||
unsigned int maxdata;
|
||||
comedi_range *range;
|
||||
unsigned int maxdata;
|
||||
comedi_range *range;
|
||||
};
|
||||
|
||||
struct comedi_direction {
|
||||
int subdevice; ///< Comedi subdevice
|
||||
int buffer_size; ///< Comedi's kernel buffer size in kB
|
||||
int sample_size; ///< Size of a single measurement sample
|
||||
int sample_rate_hz; ///< Sample rate in Hz
|
||||
bool present; ///< Config present
|
||||
bool enabled; ///< Card is started successfully
|
||||
bool running; ///< Card is actively transfering samples
|
||||
struct timespec started; ///< Timestamp when sampling started
|
||||
struct timespec last_debug; ///< Timestamp of last debug output
|
||||
size_t counter; ///< Number of villas samples transfered
|
||||
struct comedi_chanspec *chanspecs; ///< Range and maxdata config of channels
|
||||
unsigned *chanlist; ///< Channel list in comedi's packed format
|
||||
size_t chanlist_len; ///< Number of channels for this direction
|
||||
int subdevice; ///< Comedi subdevice
|
||||
int buffer_size; ///< Comedi's kernel buffer size in kB
|
||||
int sample_size; ///< Size of a single measurement sample
|
||||
int sample_rate_hz; ///< Sample rate in Hz
|
||||
bool present; ///< Config present
|
||||
bool enabled; ///< Card is started successfully
|
||||
bool running; ///< Card is actively transfering samples
|
||||
struct timespec started; ///< Timestamp when sampling started
|
||||
struct timespec last_debug; ///< Timestamp of last debug output
|
||||
size_t counter; ///< Number of villas samples transfered
|
||||
struct comedi_chanspec *chanspecs; ///< Range and maxdata config of channels
|
||||
unsigned *chanlist; ///< Channel list in comedi's packed format
|
||||
size_t chanlist_len; ///< Number of channels for this direction
|
||||
|
||||
char* buffer;
|
||||
char* bufptr;
|
||||
char *buffer;
|
||||
char *bufptr;
|
||||
};
|
||||
|
||||
struct comedi {
|
||||
char *device;
|
||||
struct comedi_direction in, out;
|
||||
comedi_t *dev;
|
||||
char *device;
|
||||
struct comedi_direction in, out;
|
||||
comedi_t *dev;
|
||||
|
||||
#if COMEDI_USE_READ
|
||||
char *buf;
|
||||
char *bufptr;
|
||||
char *buf;
|
||||
char *bufptr;
|
||||
#else
|
||||
char *map;
|
||||
size_t bufpos;
|
||||
size_t front;
|
||||
size_t back;
|
||||
char *map;
|
||||
size_t bufpos;
|
||||
size_t front;
|
||||
size_t back;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
char * comedi_print(NodeCompat *n);
|
||||
char *comedi_print(NodeCompat *n);
|
||||
|
||||
int comedi_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
|
@ -73,9 +72,9 @@ int comedi_stop(NodeCompat *n);
|
|||
|
||||
int comedi_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
int comedi_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int comedi_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int comedi_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int comedi_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
|
||||
#include <thread>
|
||||
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/task.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <villas/common.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/config.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <villas/task.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -29,37 +29,38 @@ class SuperNode;
|
|||
#include <villas/nodes/ethercat_config.hpp>
|
||||
|
||||
extern "C" {
|
||||
#include <ecrt.h>
|
||||
#include <ecrt.h>
|
||||
}
|
||||
|
||||
#define DEFAULT_ETHERCAT_QUEUE_LENGTH (DEFAULT_QUEUE_LENGTH * 64)
|
||||
#define DEFAULT_ETHERCAT_QUEUE_LENGTH (DEFAULT_QUEUE_LENGTH * 64)
|
||||
|
||||
// Internal data per ethercat node
|
||||
struct ethercat {
|
||||
// Settings
|
||||
double rate;
|
||||
// Settings
|
||||
double rate;
|
||||
|
||||
struct {
|
||||
unsigned num_channels;
|
||||
double range;
|
||||
unsigned position;
|
||||
unsigned product_code; // Product ID of EtherCAT slave
|
||||
unsigned vendor_id; // Vendor ID of EtherCAT slave
|
||||
struct {
|
||||
unsigned num_channels;
|
||||
double range;
|
||||
unsigned position;
|
||||
unsigned product_code; // Product ID of EtherCAT slave
|
||||
unsigned vendor_id; // Vendor ID of EtherCAT slave
|
||||
|
||||
ec_slave_config_t *sc;
|
||||
unsigned *offsets; // Offsets for PDO entries
|
||||
} in, out;
|
||||
ec_slave_config_t *sc;
|
||||
unsigned *offsets; // Offsets for PDO entries
|
||||
} in, out;
|
||||
|
||||
ec_domain_t *domain;
|
||||
ec_pdo_entry_reg_t *domain_regs;
|
||||
uint8_t *domain_pd; // Process data
|
||||
ec_domain_t *domain;
|
||||
ec_pdo_entry_reg_t *domain_regs;
|
||||
uint8_t *domain_pd; // Process data
|
||||
|
||||
std::thread thread; // Cyclic task thread
|
||||
struct Task task; // Periodic timer
|
||||
struct Pool pool;
|
||||
struct CQueueSignalled queue; // For samples which are received from WebSockets
|
||||
std::thread thread; // Cyclic task thread
|
||||
struct Task task; // Periodic timer
|
||||
struct Pool pool;
|
||||
struct CQueueSignalled
|
||||
queue; // For samples which are received from WebSockets
|
||||
|
||||
std::atomic<struct Sample *> send; // Last sample to be sent via EtherCAT
|
||||
std::atomic<struct Sample *> send; // Last sample to be sent via EtherCAT
|
||||
};
|
||||
|
||||
// Internal datastructures
|
||||
|
@ -84,11 +85,11 @@ int ethercat_stop(NodeCompat *n);
|
|||
|
||||
int ethercat_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
char * ethercat_print(NodeCompat *n);
|
||||
char *ethercat_print(NodeCompat *n);
|
||||
|
||||
int ethercat_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int ethercat_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int ethercat_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int ethercat_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -33,8 +33,7 @@
|
|||
* Revision number: 0x00140000
|
||||
*/
|
||||
|
||||
static
|
||||
ec_pdo_entry_info_t slave_3_pdo_entries[] = {
|
||||
static ec_pdo_entry_info_t slave_3_pdo_entries[] = {
|
||||
{0x7000, 0x01, 16}, // Analog output
|
||||
{0x7010, 0x01, 16}, // Analog output
|
||||
{0x7020, 0x01, 16}, // Analog output
|
||||
|
@ -45,8 +44,7 @@ ec_pdo_entry_info_t slave_3_pdo_entries[] = {
|
|||
{0x7070, 0x01, 16}, // Analog output
|
||||
};
|
||||
|
||||
static
|
||||
ec_pdo_info_t slave_3_pdos[] = {
|
||||
static ec_pdo_info_t slave_3_pdos[] = {
|
||||
{0x1600, 1, slave_3_pdo_entries + 0}, // AO RxPDO-Map Outputs Ch.1
|
||||
{0x1601, 1, slave_3_pdo_entries + 1}, // AO RxPDO-Map Outputs Ch.2
|
||||
{0x1602, 1, slave_3_pdo_entries + 2}, // AO RxPDO-Map Outputs Ch.3
|
||||
|
@ -57,14 +55,12 @@ ec_pdo_info_t slave_3_pdos[] = {
|
|||
{0x1607, 1, slave_3_pdo_entries + 7}, // AO RxPDO-Map Outputs Ch.8
|
||||
};
|
||||
|
||||
static
|
||||
ec_sync_info_t slave_3_syncs[] = {
|
||||
static ec_sync_info_t slave_3_syncs[] = {
|
||||
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
|
||||
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
|
||||
{2, EC_DIR_OUTPUT, 8, slave_3_pdos + 0, EC_WD_DISABLE},
|
||||
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
|
||||
{0xff}
|
||||
};
|
||||
{0xff}};
|
||||
|
||||
/* Master 0, Slave 4, "EL3008"
|
||||
* Vendor ID: 0x00000002
|
||||
|
@ -72,93 +68,91 @@ ec_sync_info_t slave_3_syncs[] = {
|
|||
* Revision number: 0x00150000
|
||||
*/
|
||||
|
||||
static
|
||||
ec_pdo_entry_info_t slave_4_pdo_entries[] = {
|
||||
{0x6000, 0x01, 1}, // Underrange
|
||||
{0x6000, 0x02, 1}, // Overrange
|
||||
{0x6000, 0x03, 2}, // Limit 1
|
||||
{0x6000, 0x05, 2}, // Limit 2
|
||||
{0x6000, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6000, 0x0f, 1}, // TxPDO State
|
||||
{0x6000, 0x10, 1}, // TxPDO Toggle
|
||||
static ec_pdo_entry_info_t slave_4_pdo_entries[] = {
|
||||
{0x6000, 0x01, 1}, // Underrange
|
||||
{0x6000, 0x02, 1}, // Overrange
|
||||
{0x6000, 0x03, 2}, // Limit 1
|
||||
{0x6000, 0x05, 2}, // Limit 2
|
||||
{0x6000, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6000, 0x0f, 1}, // TxPDO State
|
||||
{0x6000, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6000, 0x11, 16}, // Value
|
||||
{0x6010, 0x01, 1}, // Underrange
|
||||
{0x6010, 0x02, 1}, // Overrange
|
||||
{0x6010, 0x03, 2}, // Limit 1
|
||||
{0x6010, 0x05, 2}, // Limit 2
|
||||
{0x6010, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6010, 0x0f, 1}, // TxPDO State
|
||||
{0x6010, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6010, 0x01, 1}, // Underrange
|
||||
{0x6010, 0x02, 1}, // Overrange
|
||||
{0x6010, 0x03, 2}, // Limit 1
|
||||
{0x6010, 0x05, 2}, // Limit 2
|
||||
{0x6010, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6010, 0x0f, 1}, // TxPDO State
|
||||
{0x6010, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6010, 0x11, 16}, // Value
|
||||
{0x6020, 0x01, 1}, // Underrange
|
||||
{0x6020, 0x02, 1}, // Overrange
|
||||
{0x6020, 0x03, 2}, // Limit 1
|
||||
{0x6020, 0x05, 2}, // Limit 2
|
||||
{0x6020, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6020, 0x0f, 1}, // TxPDO State
|
||||
{0x6020, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6020, 0x01, 1}, // Underrange
|
||||
{0x6020, 0x02, 1}, // Overrange
|
||||
{0x6020, 0x03, 2}, // Limit 1
|
||||
{0x6020, 0x05, 2}, // Limit 2
|
||||
{0x6020, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6020, 0x0f, 1}, // TxPDO State
|
||||
{0x6020, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6020, 0x11, 16}, // Value
|
||||
{0x6030, 0x01, 1}, // Underrange
|
||||
{0x6030, 0x02, 1}, // Overrange
|
||||
{0x6030, 0x03, 2}, // Limit 1
|
||||
{0x6030, 0x05, 2}, // Limit 2
|
||||
{0x6030, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6030, 0x0f, 1}, // TxPDO State
|
||||
{0x6030, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6030, 0x01, 1}, // Underrange
|
||||
{0x6030, 0x02, 1}, // Overrange
|
||||
{0x6030, 0x03, 2}, // Limit 1
|
||||
{0x6030, 0x05, 2}, // Limit 2
|
||||
{0x6030, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6030, 0x0f, 1}, // TxPDO State
|
||||
{0x6030, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6030, 0x11, 16}, // Value
|
||||
{0x6040, 0x01, 1}, // Underrange
|
||||
{0x6040, 0x02, 1}, // Overrange
|
||||
{0x6040, 0x03, 2}, // Limit 1
|
||||
{0x6040, 0x05, 2}, // Limit 2
|
||||
{0x6040, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6040, 0x0f, 1}, // TxPDO State
|
||||
{0x6040, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6040, 0x01, 1}, // Underrange
|
||||
{0x6040, 0x02, 1}, // Overrange
|
||||
{0x6040, 0x03, 2}, // Limit 1
|
||||
{0x6040, 0x05, 2}, // Limit 2
|
||||
{0x6040, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6040, 0x0f, 1}, // TxPDO State
|
||||
{0x6040, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6040, 0x11, 16}, // Value
|
||||
{0x6050, 0x01, 1}, // Underrange
|
||||
{0x6050, 0x02, 1}, // Overrange
|
||||
{0x6050, 0x03, 2}, // Limit 1
|
||||
{0x6050, 0x05, 2}, // Limit 2
|
||||
{0x6050, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6050, 0x0f, 1}, // TxPDO State
|
||||
{0x6050, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6050, 0x01, 1}, // Underrange
|
||||
{0x6050, 0x02, 1}, // Overrange
|
||||
{0x6050, 0x03, 2}, // Limit 1
|
||||
{0x6050, 0x05, 2}, // Limit 2
|
||||
{0x6050, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6050, 0x0f, 1}, // TxPDO State
|
||||
{0x6050, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6050, 0x11, 16}, // Value
|
||||
{0x6060, 0x01, 1}, // Underrange
|
||||
{0x6060, 0x02, 1}, // Overrange
|
||||
{0x6060, 0x03, 2}, // Limit 1
|
||||
{0x6060, 0x05, 2}, // Limit 2
|
||||
{0x6060, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6060, 0x0f, 1}, // TxPDO State
|
||||
{0x6060, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6060, 0x01, 1}, // Underrange
|
||||
{0x6060, 0x02, 1}, // Overrange
|
||||
{0x6060, 0x03, 2}, // Limit 1
|
||||
{0x6060, 0x05, 2}, // Limit 2
|
||||
{0x6060, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6060, 0x0f, 1}, // TxPDO State
|
||||
{0x6060, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6060, 0x11, 16}, // Value
|
||||
{0x6070, 0x01, 1}, // Underrange
|
||||
{0x6070, 0x02, 1}, // Overrange
|
||||
{0x6070, 0x03, 2}, // Limit 1
|
||||
{0x6070, 0x05, 2}, // Limit 2
|
||||
{0x6070, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6070, 0x0f, 1}, // TxPDO State
|
||||
{0x6070, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6070, 0x01, 1}, // Underrange
|
||||
{0x6070, 0x02, 1}, // Overrange
|
||||
{0x6070, 0x03, 2}, // Limit 1
|
||||
{0x6070, 0x05, 2}, // Limit 2
|
||||
{0x6070, 0x07, 1}, // Error
|
||||
{0x0000, 0x00, 1}, // Gap
|
||||
{0x0000, 0x00, 6}, // Gap
|
||||
{0x6070, 0x0f, 1}, // TxPDO State
|
||||
{0x6070, 0x10, 1}, // TxPDO Toggle
|
||||
{0x6070, 0x11, 16}, // Value
|
||||
};
|
||||
|
||||
static
|
||||
ec_pdo_info_t slave_4_pdos[] = {
|
||||
{0x1a00, 10, slave_4_pdo_entries + 0}, // AI TxPDO-Map Standard Ch.1
|
||||
static ec_pdo_info_t slave_4_pdos[] = {
|
||||
{0x1a00, 10, slave_4_pdo_entries + 0}, // AI TxPDO-Map Standard Ch.1
|
||||
{0x1a02, 10, slave_4_pdo_entries + 10}, // AI TxPDO-Map Standard Ch.2
|
||||
{0x1a04, 10, slave_4_pdo_entries + 20}, // AI TxPDO-Map Standard Ch.3
|
||||
{0x1a06, 10, slave_4_pdo_entries + 30}, // AI TxPDO-Map Standard Ch.4
|
||||
|
@ -168,11 +162,9 @@ ec_pdo_info_t slave_4_pdos[] = {
|
|||
{0x1a0e, 10, slave_4_pdo_entries + 70}, // AI TxPDO-Map Standard Ch.8
|
||||
};
|
||||
|
||||
static
|
||||
ec_sync_info_t slave_4_syncs[] = {
|
||||
static ec_sync_info_t slave_4_syncs[] = {
|
||||
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
|
||||
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
|
||||
{2, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
|
||||
{3, EC_DIR_INPUT, 8, slave_4_pdos + 0, EC_WD_DISABLE},
|
||||
{0xff}
|
||||
};
|
||||
{0xff}};
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
|
||||
namespace villas {
|
||||
|
@ -23,72 +23,64 @@ struct Sample;
|
|||
class ExampleNode : public Node {
|
||||
|
||||
protected:
|
||||
// Place any configuration and per-node state here
|
||||
// Place any configuration and per-node state here
|
||||
|
||||
// Settings
|
||||
int setting1;
|
||||
// Settings
|
||||
int setting1;
|
||||
|
||||
std::string setting2;
|
||||
std::string setting2;
|
||||
|
||||
// States
|
||||
int state1;
|
||||
struct timespec start_time;
|
||||
// States
|
||||
int state1;
|
||||
struct timespec start_time;
|
||||
|
||||
virtual
|
||||
int _read(struct Sample *smps[], unsigned cnt);
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int _write(struct Sample *smps[], unsigned cnt);
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
ExampleNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
ExampleNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
/* All of the following virtual-declared functions are optional.
|
||||
/* All of the following virtual-declared functions are optional.
|
||||
* Have a look at node.hpp/node.cpp for the default behaviour.
|
||||
*/
|
||||
|
||||
virtual
|
||||
~ExampleNode();
|
||||
virtual ~ExampleNode();
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
virtual int prepare();
|
||||
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
// Validate node configuration
|
||||
virtual
|
||||
int check();
|
||||
// Validate node configuration
|
||||
virtual int check();
|
||||
|
||||
virtual
|
||||
int start();
|
||||
virtual int start();
|
||||
|
||||
// virtual
|
||||
// int stop();
|
||||
// virtual
|
||||
// int stop();
|
||||
|
||||
// virtual
|
||||
// int pause();
|
||||
// virtual
|
||||
// int pause();
|
||||
|
||||
// virtual
|
||||
// int resume();
|
||||
// virtual
|
||||
// int resume();
|
||||
|
||||
// virtual
|
||||
// int restart();
|
||||
// virtual
|
||||
// int restart();
|
||||
|
||||
// virtual
|
||||
// int reverse();
|
||||
// virtual
|
||||
// int reverse();
|
||||
|
||||
// virtual
|
||||
// std::vector<int> getPollFDs();
|
||||
// virtual
|
||||
// std::vector<int> getPollFDs();
|
||||
|
||||
// virtual
|
||||
// std::vector<int> getNetemFDs();
|
||||
// virtual
|
||||
// std::vector<int> getNetemFDs();
|
||||
|
||||
// virtual
|
||||
// struct villas::node::memory::Type * getMemoryType();
|
||||
// virtual
|
||||
// struct villas::node::memory::Type * getMemoryType();
|
||||
|
||||
virtual
|
||||
const std::string & getDetails();
|
||||
virtual const std::string &getDetails();
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/popen.hpp>
|
||||
#include <villas/format.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -20,55 +20,42 @@ struct Sample;
|
|||
class ExecNode : public Node {
|
||||
|
||||
protected:
|
||||
std::unique_ptr<villas::utils::Popen> proc;
|
||||
std::unique_ptr<Format> formatter;
|
||||
std::unique_ptr<villas::utils::Popen> proc;
|
||||
std::unique_ptr<Format> formatter;
|
||||
|
||||
FILE *stream_in, *stream_out;
|
||||
FILE *stream_in, *stream_out;
|
||||
|
||||
bool flush;
|
||||
bool shell;
|
||||
bool flush;
|
||||
bool shell;
|
||||
|
||||
std::string working_dir;
|
||||
std::string command;
|
||||
std::string working_dir;
|
||||
std::string command;
|
||||
|
||||
villas::utils::Popen::arg_list arguments;
|
||||
villas::utils::Popen::env_map environment;
|
||||
villas::utils::Popen::arg_list arguments;
|
||||
villas::utils::Popen::env_map environment;
|
||||
|
||||
virtual
|
||||
int _read(struct Sample * smps[], unsigned cnt);
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int _write(struct Sample * smps[], unsigned cnt);
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
ExecNode(const uuid_t &id = {}, const std::string &name = "") :
|
||||
Node(id, name),
|
||||
stream_in(nullptr),
|
||||
stream_out(nullptr),
|
||||
flush(true),
|
||||
shell(false)
|
||||
{ }
|
||||
ExecNode(const uuid_t &id = {}, const std::string &name = "")
|
||||
: Node(id, name), stream_in(nullptr), stream_out(nullptr), flush(true),
|
||||
shell(false) {}
|
||||
|
||||
virtual
|
||||
~ExecNode();
|
||||
virtual ~ExecNode();
|
||||
|
||||
virtual
|
||||
const std::string & getDetails();
|
||||
virtual const std::string &getDetails();
|
||||
|
||||
virtual
|
||||
int start();
|
||||
virtual int start();
|
||||
|
||||
virtual
|
||||
int stop();
|
||||
virtual int stop();
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
virtual int prepare();
|
||||
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs();
|
||||
virtual std::vector<int> getPollFDs();
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -18,43 +18,48 @@ namespace node {
|
|||
// Forward declarations
|
||||
class NodeCompat;
|
||||
|
||||
#define FILE_MAX_PATHLEN 512
|
||||
#define FILE_MAX_PATHLEN 512
|
||||
|
||||
struct file {
|
||||
Format *formatter;
|
||||
FILE *stream_in;
|
||||
FILE *stream_out;
|
||||
Format *formatter;
|
||||
FILE *stream_in;
|
||||
FILE *stream_out;
|
||||
|
||||
char *uri_tmpl; // Format string for file name.
|
||||
char *uri; // Real file name.
|
||||
char *uri_tmpl; // Format string for file name.
|
||||
char *uri; // Real file name.
|
||||
|
||||
unsigned skip_lines; // Skip the first n-th lines/samples of the file.
|
||||
int flush; // Flush / upload file contents after each write.
|
||||
struct Task task; // Timer file descriptor. Blocks until 1 / rate seconds are elapsed.
|
||||
double rate; // The read rate.
|
||||
size_t buffer_size_out; // Defines size of output stream buffer. No buffer is created if value is set to zero.
|
||||
size_t buffer_size_in; // Defines size of input stream buffer. No buffer is created if value is set to zero.
|
||||
unsigned skip_lines; // Skip the first n-th lines/samples of the file.
|
||||
int flush; // Flush / upload file contents after each write.
|
||||
struct Task
|
||||
task; // Timer file descriptor. Blocks until 1 / rate seconds are elapsed.
|
||||
double rate; // The read rate.
|
||||
size_t
|
||||
buffer_size_out; // Defines size of output stream buffer. No buffer is created if value is set to zero.
|
||||
size_t
|
||||
buffer_size_in; // Defines size of input stream buffer. No buffer is created if value is set to zero.
|
||||
|
||||
enum class EpochMode {
|
||||
DIRECT,
|
||||
WAIT,
|
||||
RELATIVE,
|
||||
ABSOLUTE,
|
||||
ORIGINAL
|
||||
} epoch_mode; // Specifies how file::offset is calculated.
|
||||
enum class EpochMode {
|
||||
DIRECT,
|
||||
WAIT,
|
||||
RELATIVE,
|
||||
ABSOLUTE,
|
||||
ORIGINAL
|
||||
} epoch_mode; // Specifies how file::offset is calculated.
|
||||
|
||||
enum class EOFBehaviour {
|
||||
STOP, // Terminate when EOF is reached.
|
||||
REWIND, // Rewind the file when EOF is reached.
|
||||
SUSPEND // Blocking wait when EOF is reached.
|
||||
} eof_mode;
|
||||
enum class EOFBehaviour {
|
||||
STOP, // Terminate when EOF is reached.
|
||||
REWIND, // Rewind the file when EOF is reached.
|
||||
SUSPEND // Blocking wait when EOF is reached.
|
||||
} eof_mode;
|
||||
|
||||
struct timespec first; // The first timestamp in the file file::{read,write}::uri
|
||||
struct timespec epoch; // The epoch timestamp from the configuration.
|
||||
struct timespec offset; // An offset between the timestamp in the input file and the current time
|
||||
struct timespec
|
||||
first; // The first timestamp in the file file::{read,write}::uri
|
||||
struct timespec epoch; // The epoch timestamp from the configuration.
|
||||
struct timespec
|
||||
offset; // An offset between the timestamp in the input file and the current time
|
||||
};
|
||||
|
||||
char * file_print(NodeCompat *n);
|
||||
char *file_print(NodeCompat *n);
|
||||
|
||||
int file_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
|
@ -68,9 +73,9 @@ int file_destroy(NodeCompat *n);
|
|||
|
||||
int file_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
int file_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int file_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int file_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int file_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
|
||||
#include <villas/fpga/card.hpp>
|
||||
#include <villas/fpga/pcie_card.hpp>
|
||||
#include <villas/fpga/node.hpp>
|
||||
#include <villas/fpga/ips/dma.hpp>
|
||||
#include <villas/fpga/node.hpp>
|
||||
#include <villas/fpga/pcie_card.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -26,89 +26,68 @@ namespace node {
|
|||
class FpgaNode : public Node {
|
||||
|
||||
protected:
|
||||
int irqFd;
|
||||
int coalesce;
|
||||
bool polling;
|
||||
int irqFd;
|
||||
int coalesce;
|
||||
bool polling;
|
||||
|
||||
std::shared_ptr<fpga::PCIeCard> card;
|
||||
std::shared_ptr<fpga::PCIeCard> card;
|
||||
|
||||
std::shared_ptr<fpga::ip::Dma> dma;
|
||||
std::shared_ptr<fpga::ip::Node> intf;
|
||||
std::shared_ptr<fpga::ip::Dma> dma;
|
||||
std::shared_ptr<fpga::ip::Node> intf;
|
||||
|
||||
std::unique_ptr<const MemoryBlock> blockRx;
|
||||
std::unique_ptr<const MemoryBlock> blockTx;
|
||||
std::unique_ptr<const MemoryBlock> blockRx;
|
||||
std::unique_ptr<const MemoryBlock> blockTx;
|
||||
|
||||
// Config only
|
||||
std::string cardName;
|
||||
std::string intfName;
|
||||
std::string dmaName;
|
||||
// Config only
|
||||
std::string cardName;
|
||||
std::string intfName;
|
||||
std::string dmaName;
|
||||
|
||||
protected:
|
||||
virtual
|
||||
int _read(Sample *smps[], unsigned cnt);
|
||||
virtual int _read(Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int _write(Sample *smps[], unsigned cnt);
|
||||
virtual int _write(Sample *smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
FpgaNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
FpgaNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
virtual
|
||||
~FpgaNode();
|
||||
virtual ~FpgaNode();
|
||||
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
virtual
|
||||
const std::string & getDetails();
|
||||
virtual const std::string &getDetails();
|
||||
|
||||
virtual
|
||||
int check();
|
||||
virtual int check();
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
virtual int prepare();
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs();
|
||||
virtual std::vector<int> getPollFDs();
|
||||
};
|
||||
|
||||
class FpgaNodeFactory : public NodeFactory {
|
||||
|
||||
public:
|
||||
using NodeFactory::NodeFactory;
|
||||
using NodeFactory::NodeFactory;
|
||||
|
||||
virtual
|
||||
Node * make(const uuid_t &id = {}, const std::string &nme = "")
|
||||
{
|
||||
auto *n = new FpgaNode(id, nme);
|
||||
virtual Node *make(const uuid_t &id = {}, const std::string &nme = "") {
|
||||
auto *n = new FpgaNode(id, nme);
|
||||
|
||||
init(n);
|
||||
init(n);
|
||||
|
||||
return n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
virtual
|
||||
int getFlags() const
|
||||
{
|
||||
return (int) NodeFactory::Flags::SUPPORTS_READ |
|
||||
(int) NodeFactory::Flags::SUPPORTS_WRITE |
|
||||
(int) NodeFactory::Flags::SUPPORTS_POLL;
|
||||
}
|
||||
virtual int getFlags() const {
|
||||
return (int)NodeFactory::Flags::SUPPORTS_READ |
|
||||
(int)NodeFactory::Flags::SUPPORTS_WRITE |
|
||||
(int)NodeFactory::Flags::SUPPORTS_POLL;
|
||||
}
|
||||
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return "fpga";
|
||||
}
|
||||
virtual std::string getName() const { return "fpga"; }
|
||||
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return "VILLASfpga";
|
||||
}
|
||||
virtual std::string getDescription() const { return "VILLASfpga"; }
|
||||
|
||||
virtual
|
||||
int start(SuperNode *sn);
|
||||
virtual int start(SuperNode *sn);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,18 +7,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <array>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/signal.hpp>
|
||||
#include <lib60870/iec60870_common.h>
|
||||
#include <lib60870/cs101_information_objects.h>
|
||||
#include <lib60870/cs104_slave.h>
|
||||
#include <lib60870/iec60870_common.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/signal.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -27,167 +27,185 @@ namespace iec60870 {
|
|||
/// A supported CS101 information data type
|
||||
class ASDUData {
|
||||
public:
|
||||
enum Type {
|
||||
SINGLE_POINT = M_SP_NA_1, // SinglePointInformation
|
||||
SINGLE_POINT_WITH_TIMESTAMP = M_SP_TB_1, // SinglePointWithCP56Time2a
|
||||
DOUBLE_POINT = M_DP_NA_1, // DoublePointInformation
|
||||
DOUBLE_POINT_WITH_TIMESTAMP = M_DP_TB_1, // DoublePointWithCP56Time2a
|
||||
SCALED_INT = M_ME_NB_1, // MeasuredValueScaled
|
||||
SCALED_INT_WITH_TIMESTAMP = M_ME_TE_1, // MeasuredValueScaledWithCP56Time2a
|
||||
NORMALIZED_FLOAT = M_ME_NA_1, // MeasuredValueNormalized
|
||||
NORMALIZED_FLOAT_WITH_TIMESTAMP = M_ME_TD_1, // MeasuredValueNormalizedWithCP56Time2a
|
||||
SHORT_FLOAT = M_ME_NC_1, // MeasuredValueShort
|
||||
SHORT_FLOAT_WITH_TIMESTAMP = M_ME_TF_1, // MeasuredValueShortWithCP56Time2a
|
||||
};
|
||||
enum Type {
|
||||
SINGLE_POINT = M_SP_NA_1, // SinglePointInformation
|
||||
SINGLE_POINT_WITH_TIMESTAMP = M_SP_TB_1, // SinglePointWithCP56Time2a
|
||||
DOUBLE_POINT = M_DP_NA_1, // DoublePointInformation
|
||||
DOUBLE_POINT_WITH_TIMESTAMP = M_DP_TB_1, // DoublePointWithCP56Time2a
|
||||
SCALED_INT = M_ME_NB_1, // MeasuredValueScaled
|
||||
SCALED_INT_WITH_TIMESTAMP = M_ME_TE_1, // MeasuredValueScaledWithCP56Time2a
|
||||
NORMALIZED_FLOAT = M_ME_NA_1, // MeasuredValueNormalized
|
||||
NORMALIZED_FLOAT_WITH_TIMESTAMP =
|
||||
M_ME_TD_1, // MeasuredValueNormalizedWithCP56Time2a
|
||||
SHORT_FLOAT = M_ME_NC_1, // MeasuredValueShort
|
||||
SHORT_FLOAT_WITH_TIMESTAMP = M_ME_TF_1, // MeasuredValueShortWithCP56Time2a
|
||||
};
|
||||
|
||||
struct Sample {
|
||||
SignalData signal_data;
|
||||
QualityDescriptor quality;
|
||||
std::optional<timespec> timestamp;
|
||||
};
|
||||
struct Sample {
|
||||
SignalData signal_data;
|
||||
QualityDescriptor quality;
|
||||
std::optional<timespec> timestamp;
|
||||
};
|
||||
|
||||
// Parse the config json
|
||||
static
|
||||
ASDUData parse(json_t *json_signal, std::optional<ASDUData> last_data, bool duplicate_ioa_is_sequence);
|
||||
// Parse the config json
|
||||
static ASDUData parse(json_t *json_signal, std::optional<ASDUData> last_data,
|
||||
bool duplicate_ioa_is_sequence);
|
||||
|
||||
// Does this data include a timestamp
|
||||
bool hasTimestamp() const;
|
||||
// Does this data include a timestamp
|
||||
bool hasTimestamp() const;
|
||||
|
||||
// The IEC104 type
|
||||
ASDUData::Type type() const;
|
||||
// The IEC104 type
|
||||
ASDUData::Type type() const;
|
||||
|
||||
// The config file identifier for this type
|
||||
char const * name() const;
|
||||
// The config file identifier for this type
|
||||
char const *name() const;
|
||||
|
||||
// Get equivalent IEC104 type without timestamp (e.g. for general interrogation response)
|
||||
ASDUData::Type typeWithoutTimestamp() const;
|
||||
// Get equivalent IEC104 type without timestamp (e.g. for general interrogation response)
|
||||
ASDUData::Type typeWithoutTimestamp() const;
|
||||
|
||||
// Get equivalent ASDUData without timestamp (e.g. for general interrogation response)
|
||||
ASDUData withoutTimestamp() const;
|
||||
// Get equivalent ASDUData without timestamp (e.g. for general interrogation response)
|
||||
ASDUData withoutTimestamp() const;
|
||||
|
||||
// Corresponding signal type
|
||||
SignalType signalType() const;
|
||||
// Corresponding signal type
|
||||
SignalType signalType() const;
|
||||
|
||||
// Check if ASDU contains this data
|
||||
std::optional<ASDUData::Sample> checkASDU(CS101_ASDU const &asdu) const;
|
||||
// Check if ASDU contains this data
|
||||
std::optional<ASDUData::Sample> checkASDU(CS101_ASDU const &asdu) const;
|
||||
|
||||
// Add SignalData to an ASDU, returns false when sample couldn't be added (insufficient space in ASDU)
|
||||
bool addSampleToASDU(CS101_ASDU &asdu, ASDUData::Sample sample) const;
|
||||
// Add SignalData to an ASDU, returns false when sample couldn't be added (insufficient space in ASDU)
|
||||
bool addSampleToASDU(CS101_ASDU &asdu, ASDUData::Sample sample) const;
|
||||
|
||||
// Every value in an ASDU has an associated "information object address" (ioa)
|
||||
int ioa;
|
||||
// Every value in an ASDU has an associated "information object address" (ioa)
|
||||
int ioa;
|
||||
|
||||
// Start of the ioa sequence
|
||||
int ioa_sequence_start;
|
||||
|
||||
// Start of the ioa sequence
|
||||
int ioa_sequence_start;
|
||||
private:
|
||||
struct Descriptor {
|
||||
ASDUData::Type type;
|
||||
char const *name;
|
||||
char const *type_id;
|
||||
bool has_timestamp;
|
||||
ASDUData::Type type_without_timestamp;
|
||||
SignalType signal_type;
|
||||
};
|
||||
struct Descriptor {
|
||||
ASDUData::Type type;
|
||||
char const *name;
|
||||
char const *type_id;
|
||||
bool has_timestamp;
|
||||
ASDUData::Type type_without_timestamp;
|
||||
SignalType signal_type;
|
||||
};
|
||||
|
||||
inline static
|
||||
std::array const descriptors {
|
||||
ASDUData::Descriptor { Type::SINGLE_POINT, "single-point", "M_SP_NA_1", false, Type::SINGLE_POINT, SignalType::BOOLEAN },
|
||||
ASDUData::Descriptor { Type::SINGLE_POINT_WITH_TIMESTAMP, "single-point", "M_SP_TB_1", true, Type::SINGLE_POINT, SignalType::BOOLEAN },
|
||||
ASDUData::Descriptor { Type::DOUBLE_POINT, "double-point", "M_DP_NA_1", false, Type::DOUBLE_POINT, SignalType::INTEGER },
|
||||
ASDUData::Descriptor { Type::DOUBLE_POINT_WITH_TIMESTAMP, "double-point", "M_DP_TB_1", true, Type::DOUBLE_POINT, SignalType::INTEGER },
|
||||
ASDUData::Descriptor { Type::SCALED_INT, "scaled-int", "M_ME_NB_1", false, Type::SCALED_INT, SignalType::INTEGER },
|
||||
ASDUData::Descriptor { Type::SCALED_INT_WITH_TIMESTAMP, "scaled-int", "M_ME_TE_1", true, Type::SCALED_INT, SignalType::INTEGER },
|
||||
ASDUData::Descriptor { Type::NORMALIZED_FLOAT, "normalized-float", "M_ME_NA_1", false, Type::NORMALIZED_FLOAT, SignalType::FLOAT },
|
||||
ASDUData::Descriptor { Type::NORMALIZED_FLOAT_WITH_TIMESTAMP, "normalized-float", "M_ME_TD_1", true, Type::NORMALIZED_FLOAT, SignalType::FLOAT },
|
||||
ASDUData::Descriptor { Type::SHORT_FLOAT, "short-float", "M_ME_NC_1", false, Type::SHORT_FLOAT, SignalType::FLOAT },
|
||||
ASDUData::Descriptor { Type::SHORT_FLOAT_WITH_TIMESTAMP, "short-float", "M_ME_TF_1", true, Type::SHORT_FLOAT, SignalType::FLOAT },
|
||||
};
|
||||
inline static std::array const descriptors{
|
||||
ASDUData::Descriptor{Type::SINGLE_POINT, "single-point", "M_SP_NA_1",
|
||||
false, Type::SINGLE_POINT, SignalType::BOOLEAN},
|
||||
ASDUData::Descriptor{Type::SINGLE_POINT_WITH_TIMESTAMP, "single-point",
|
||||
"M_SP_TB_1", true, Type::SINGLE_POINT,
|
||||
SignalType::BOOLEAN},
|
||||
ASDUData::Descriptor{Type::DOUBLE_POINT, "double-point", "M_DP_NA_1",
|
||||
false, Type::DOUBLE_POINT, SignalType::INTEGER},
|
||||
ASDUData::Descriptor{Type::DOUBLE_POINT_WITH_TIMESTAMP, "double-point",
|
||||
"M_DP_TB_1", true, Type::DOUBLE_POINT,
|
||||
SignalType::INTEGER},
|
||||
ASDUData::Descriptor{Type::SCALED_INT, "scaled-int", "M_ME_NB_1", false,
|
||||
Type::SCALED_INT, SignalType::INTEGER},
|
||||
ASDUData::Descriptor{Type::SCALED_INT_WITH_TIMESTAMP, "scaled-int",
|
||||
"M_ME_TE_1", true, Type::SCALED_INT,
|
||||
SignalType::INTEGER},
|
||||
ASDUData::Descriptor{Type::NORMALIZED_FLOAT, "normalized-float",
|
||||
"M_ME_NA_1", false, Type::NORMALIZED_FLOAT,
|
||||
SignalType::FLOAT},
|
||||
ASDUData::Descriptor{Type::NORMALIZED_FLOAT_WITH_TIMESTAMP,
|
||||
"normalized-float", "M_ME_TD_1", true,
|
||||
Type::NORMALIZED_FLOAT, SignalType::FLOAT},
|
||||
ASDUData::Descriptor{Type::SHORT_FLOAT, "short-float", "M_ME_NC_1", false,
|
||||
Type::SHORT_FLOAT, SignalType::FLOAT},
|
||||
ASDUData::Descriptor{Type::SHORT_FLOAT_WITH_TIMESTAMP, "short-float",
|
||||
"M_ME_TF_1", true, Type::SHORT_FLOAT,
|
||||
SignalType::FLOAT},
|
||||
};
|
||||
|
||||
ASDUData(ASDUData::Descriptor const *descriptor, int ioa, int ioa_sequence_start);
|
||||
ASDUData(ASDUData::Descriptor const *descriptor, int ioa,
|
||||
int ioa_sequence_start);
|
||||
|
||||
// Lookup datatype for config key asdu_type
|
||||
static
|
||||
std::optional<ASDUData> lookupName(char const *name, bool with_timestamp, int ioa, int ioa_sequence_start);
|
||||
// Lookup datatype for config key asdu_type
|
||||
static std::optional<ASDUData> lookupName(char const *name,
|
||||
bool with_timestamp, int ioa,
|
||||
int ioa_sequence_start);
|
||||
|
||||
// Lookup datatype for config key asdu_type_id
|
||||
static
|
||||
std::optional<ASDUData> lookupTypeId(char const *type_id, int ioa, int ioa_sequence_start);
|
||||
// Lookup datatype for config key asdu_type_id
|
||||
static std::optional<ASDUData> lookupTypeId(char const *type_id, int ioa,
|
||||
int ioa_sequence_start);
|
||||
|
||||
// Lookup datatype for numeric type identifier
|
||||
static
|
||||
std::optional<ASDUData> lookupType(int type, int ioa, int ioa_sequence_start);
|
||||
// Lookup datatype for numeric type identifier
|
||||
static std::optional<ASDUData> lookupType(int type, int ioa,
|
||||
int ioa_sequence_start);
|
||||
|
||||
// Descriptor within the descriptors table above
|
||||
ASDUData::Descriptor const *descriptor;
|
||||
// Descriptor within the descriptors table above
|
||||
ASDUData::Descriptor const *descriptor;
|
||||
};
|
||||
|
||||
class SlaveNode : public Node {
|
||||
protected:
|
||||
struct Server {
|
||||
// Slave state
|
||||
enum { NONE, STOPPED, READY } state;
|
||||
struct Server {
|
||||
// Slave state
|
||||
enum { NONE, STOPPED, READY } state;
|
||||
|
||||
// Config (use explicit defaults)
|
||||
std::string local_address;
|
||||
int local_port;
|
||||
int common_address;
|
||||
int low_priority_queue;
|
||||
int high_priority_queue;
|
||||
// Config (use explicit defaults)
|
||||
std::string local_address;
|
||||
int local_port;
|
||||
int common_address;
|
||||
int low_priority_queue;
|
||||
int high_priority_queue;
|
||||
|
||||
// Config (use lib60870 defaults if std::nullopt)
|
||||
std::optional<int> apci_t0;
|
||||
std::optional<int> apci_t1;
|
||||
std::optional<int> apci_t2;
|
||||
std::optional<int> apci_t3;
|
||||
std::optional<int> apci_k;
|
||||
std::optional<int> apci_w;
|
||||
// Config (use lib60870 defaults if std::nullopt)
|
||||
std::optional<int> apci_t0;
|
||||
std::optional<int> apci_t1;
|
||||
std::optional<int> apci_t2;
|
||||
std::optional<int> apci_t3;
|
||||
std::optional<int> apci_k;
|
||||
std::optional<int> apci_w;
|
||||
|
||||
// Lib60870
|
||||
CS104_Slave slave;
|
||||
CS101_AppLayerParameters asdu_app_layer_parameters;
|
||||
} server;
|
||||
// Lib60870
|
||||
CS104_Slave slave;
|
||||
CS101_AppLayerParameters asdu_app_layer_parameters;
|
||||
} server;
|
||||
|
||||
struct Output {
|
||||
bool enabled = false;
|
||||
std::vector<ASDUData> mapping;
|
||||
std::vector<ASDUData::Type> asdu_types;
|
||||
struct Output {
|
||||
bool enabled = false;
|
||||
std::vector<ASDUData> mapping;
|
||||
std::vector<ASDUData::Type> asdu_types;
|
||||
|
||||
mutable std::mutex last_values_mutex;
|
||||
std::vector<SignalData> last_values;
|
||||
} output;
|
||||
mutable std::mutex last_values_mutex;
|
||||
std::vector<SignalData> last_values;
|
||||
} output;
|
||||
|
||||
void createSlave() noexcept;
|
||||
void destroySlave() noexcept;
|
||||
void createSlave() noexcept;
|
||||
void destroySlave() noexcept;
|
||||
|
||||
void startSlave() noexcept(false);
|
||||
void stopSlave() noexcept;
|
||||
void startSlave() noexcept(false);
|
||||
void stopSlave() noexcept;
|
||||
|
||||
void debugPrintMessage(IMasterConnection connection, uint8_t *message, int message_size, bool sent) const noexcept;
|
||||
void debugPrintConnection(IMasterConnection connection, CS104_PeerConnectionEvent event) const noexcept;
|
||||
void debugPrintMessage(IMasterConnection connection, uint8_t *message,
|
||||
int message_size, bool sent) const noexcept;
|
||||
void debugPrintConnection(IMasterConnection connection,
|
||||
CS104_PeerConnectionEvent event) const noexcept;
|
||||
|
||||
bool onClockSync(IMasterConnection connection, CS101_ASDU asdu, CP56Time2a new_time) const noexcept;
|
||||
bool onInterrogation(IMasterConnection connection, CS101_ASDU asdu, uint8_t _of_inter) const noexcept;
|
||||
bool onASDU(IMasterConnection connection, CS101_ASDU asdu) const noexcept;
|
||||
bool onClockSync(IMasterConnection connection, CS101_ASDU asdu,
|
||||
CP56Time2a new_time) const noexcept;
|
||||
bool onInterrogation(IMasterConnection connection, CS101_ASDU asdu,
|
||||
uint8_t _of_inter) const noexcept;
|
||||
bool onASDU(IMasterConnection connection, CS101_ASDU asdu) const noexcept;
|
||||
|
||||
void sendPeriodicASDUsForSample(Sample const *sample) const noexcept(false);
|
||||
void sendPeriodicASDUsForSample(Sample const *sample) const noexcept(false);
|
||||
|
||||
virtual
|
||||
int _write(struct Sample *smps[], unsigned cnt) override;
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt) override;
|
||||
|
||||
public:
|
||||
SlaveNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
SlaveNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
virtual
|
||||
~SlaveNode() override;
|
||||
virtual ~SlaveNode() override;
|
||||
|
||||
virtual
|
||||
int parse(json_t *json) override;
|
||||
virtual int parse(json_t *json) override;
|
||||
|
||||
virtual
|
||||
int start() override;
|
||||
virtual int start() override;
|
||||
|
||||
virtual
|
||||
int stop() override;
|
||||
virtual int stop() override;
|
||||
};
|
||||
|
||||
} // namespace iec60870
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
#include <netinet/ether.h>
|
||||
|
||||
#include <libiec61850/hal_ethernet.h>
|
||||
#include <libiec61850/goose_receiver.h>
|
||||
#include <libiec61850/hal_ethernet.h>
|
||||
#include <libiec61850/sv_subscriber.h>
|
||||
|
||||
#include <villas/list.hpp>
|
||||
|
@ -20,7 +20,8 @@
|
|||
#include <villas/signal_list.hpp>
|
||||
|
||||
#ifndef CONFIG_GOOSE_DEFAULT_DST_ADDRESS
|
||||
#define CONFIG_GOOSE_DEFAULT_DST_ADDRESS {0x01, 0x0c, 0xcd, 0x01, 0x00, 0x01}
|
||||
#define CONFIG_GOOSE_DEFAULT_DST_ADDRESS \
|
||||
{ 0x01, 0x0c, 0xcd, 0x01, 0x00, 0x01 }
|
||||
#endif
|
||||
|
||||
namespace villas {
|
||||
|
@ -30,67 +31,67 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
enum class IEC61850Type {
|
||||
// According to IEC 61850-7-2
|
||||
BOOLEAN,
|
||||
INT8,
|
||||
INT16,
|
||||
INT32,
|
||||
INT64,
|
||||
INT8U,
|
||||
INT16U,
|
||||
INT32U,
|
||||
INT64U,
|
||||
FLOAT32,
|
||||
FLOAT64,
|
||||
ENUMERATED,
|
||||
CODED_ENUM,
|
||||
OCTET_STRING,
|
||||
VISIBLE_STRING,
|
||||
OBJECTNAME,
|
||||
OBJECTREFERENCE,
|
||||
TIMESTAMP,
|
||||
ENTRYTIME,
|
||||
// According to IEC 61850-7-2
|
||||
BOOLEAN,
|
||||
INT8,
|
||||
INT16,
|
||||
INT32,
|
||||
INT64,
|
||||
INT8U,
|
||||
INT16U,
|
||||
INT32U,
|
||||
INT64U,
|
||||
FLOAT32,
|
||||
FLOAT64,
|
||||
ENUMERATED,
|
||||
CODED_ENUM,
|
||||
OCTET_STRING,
|
||||
VISIBLE_STRING,
|
||||
OBJECTNAME,
|
||||
OBJECTREFERENCE,
|
||||
TIMESTAMP,
|
||||
ENTRYTIME,
|
||||
|
||||
// According to IEC 61850-8-1
|
||||
BITSTRING
|
||||
// According to IEC 61850-8-1
|
||||
BITSTRING
|
||||
};
|
||||
|
||||
struct iec61850_type_descriptor {
|
||||
const char *name;
|
||||
enum IEC61850Type iec_type;
|
||||
enum SignalType type;
|
||||
unsigned size;
|
||||
bool publisher;
|
||||
bool subscriber;
|
||||
const char *name;
|
||||
enum IEC61850Type iec_type;
|
||||
enum SignalType type;
|
||||
unsigned size;
|
||||
bool publisher;
|
||||
bool subscriber;
|
||||
};
|
||||
|
||||
struct iec61850_receiver {
|
||||
char *interface;
|
||||
char *interface;
|
||||
|
||||
EthernetSocket socket;
|
||||
EthernetSocket socket;
|
||||
|
||||
enum class Type {
|
||||
GOOSE,
|
||||
SAMPLED_VALUES
|
||||
} type;
|
||||
enum class Type { GOOSE, SAMPLED_VALUES } type;
|
||||
|
||||
union {
|
||||
SVReceiver sv;
|
||||
GooseReceiver goose;
|
||||
};
|
||||
union {
|
||||
SVReceiver sv;
|
||||
GooseReceiver goose;
|
||||
};
|
||||
};
|
||||
|
||||
int iec61850_type_start(villas::node::SuperNode *sn);
|
||||
|
||||
int iec61850_type_stop();
|
||||
|
||||
const struct iec61850_type_descriptor * iec61850_lookup_type(const char *name);
|
||||
const struct iec61850_type_descriptor *iec61850_lookup_type(const char *name);
|
||||
|
||||
int iec61850_parse_signals(json_t *json_signals, struct List *signals, SignalList::Ptr node_signals);
|
||||
int iec61850_parse_signals(json_t *json_signals, struct List *signals,
|
||||
SignalList::Ptr node_signals);
|
||||
|
||||
struct iec61850_receiver * iec61850_receiver_lookup(enum iec61850_receiver::Type t, const char *intf);
|
||||
struct iec61850_receiver *
|
||||
iec61850_receiver_lookup(enum iec61850_receiver::Type t, const char *intf);
|
||||
|
||||
struct iec61850_receiver * iec61850_receiver_create(enum iec61850_receiver::Type t, const char *intf);
|
||||
struct iec61850_receiver *
|
||||
iec61850_receiver_create(enum iec61850_receiver::Type t, const char *intf);
|
||||
|
||||
int iec61850_receiver_start(struct iec61850_receiver *r);
|
||||
|
||||
|
@ -98,7 +99,7 @@ int iec61850_receiver_stop(struct iec61850_receiver *r);
|
|||
|
||||
int iec61850_receiver_destroy(struct iec61850_receiver *r);
|
||||
|
||||
const struct iec61850_type_descriptor * iec61850_lookup_type(const char *name);
|
||||
const struct iec61850_type_descriptor *iec61850_lookup_type(const char *name);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -8,21 +8,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <libiec61850/goose_publisher.h>
|
||||
#include <libiec61850/goose_receiver.h>
|
||||
#include <libiec61850/goose_subscriber.h>
|
||||
#include <libiec61850/goose_publisher.h>
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <villas/signal.hpp>
|
||||
|
@ -34,82 +34,89 @@ namespace iec61850 {
|
|||
// A GooseSignal is a SignalData value with attached Metadata for the MmsType and SignalType
|
||||
class GooseSignal {
|
||||
public:
|
||||
union Meta {
|
||||
int size;
|
||||
};
|
||||
union Meta {
|
||||
int size;
|
||||
};
|
||||
|
||||
struct Descriptor {
|
||||
std::string name;
|
||||
SignalType signal_type;
|
||||
MmsType mms_type;
|
||||
Meta default_meta;
|
||||
};
|
||||
struct Descriptor {
|
||||
std::string name;
|
||||
SignalType signal_type;
|
||||
MmsType mms_type;
|
||||
Meta default_meta;
|
||||
};
|
||||
|
||||
using Type = Descriptor const *;
|
||||
using Type = Descriptor const *;
|
||||
|
||||
// The config file identifier for this type
|
||||
std::string const & name() const;
|
||||
// The config file identifier for this type
|
||||
std::string const &name() const;
|
||||
|
||||
// The type of this value
|
||||
Type type() const;
|
||||
// The type of this value
|
||||
Type type() const;
|
||||
|
||||
// Corresponding mms type
|
||||
MmsType mmsType() const;
|
||||
// Corresponding mms type
|
||||
MmsType mmsType() const;
|
||||
|
||||
// Corresponding signal type
|
||||
SignalType signalType() const;
|
||||
// Corresponding signal type
|
||||
SignalType signalType() const;
|
||||
|
||||
// Create a GooseSignal from an MmsValue
|
||||
static
|
||||
std::optional<GooseSignal> fromMmsValue(MmsValue *mms_value);
|
||||
// Create a GooseSignal from an MmsValue
|
||||
static std::optional<GooseSignal> fromMmsValue(MmsValue *mms_value);
|
||||
|
||||
// Create a GooseSignal from type name and SignalData value
|
||||
static
|
||||
std::optional<GooseSignal> fromNameAndValue(char const *name, SignalData value, std::optional<Meta> meta = std::nullopt);
|
||||
// Create a GooseSignal from type name and SignalData value
|
||||
static std::optional<GooseSignal>
|
||||
fromNameAndValue(char const *name, SignalData value,
|
||||
std::optional<Meta> meta = std::nullopt);
|
||||
|
||||
// Create a MmsValue from this GooseSignal
|
||||
MmsValue * toMmsValue() const;
|
||||
// Create a MmsValue from this GooseSignal
|
||||
MmsValue *toMmsValue() const;
|
||||
|
||||
static
|
||||
std::optional<Type> lookupMmsType(int mms_type);
|
||||
static std::optional<Type> lookupMmsType(int mms_type);
|
||||
|
||||
static
|
||||
std::optional<Type> lookupMmsTypeName(char const *name);
|
||||
static std::optional<Type> lookupMmsTypeName(char const *name);
|
||||
|
||||
GooseSignal(Type type, SignalData value, std::optional<Meta> meta = std::nullopt);
|
||||
GooseSignal(Type type, SignalData value,
|
||||
std::optional<Meta> meta = std::nullopt);
|
||||
|
||||
SignalData signal_data;
|
||||
Meta meta;
|
||||
|
||||
SignalData signal_data;
|
||||
Meta meta;
|
||||
private:
|
||||
inline static
|
||||
std::array const descriptors {
|
||||
Descriptor { "boolean", SignalType::BOOLEAN, MmsType::MMS_BOOLEAN },
|
||||
Descriptor { "int8", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 8 } },
|
||||
Descriptor { "int16", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 16 } },
|
||||
Descriptor { "int32", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 32 } },
|
||||
Descriptor { "int64", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 64 } },
|
||||
Descriptor { "int8u", SignalType::INTEGER, MmsType::MMS_UNSIGNED, {.size = 8 } },
|
||||
Descriptor { "int16u", SignalType::INTEGER, MmsType::MMS_UNSIGNED, {.size = 16 } },
|
||||
Descriptor { "int32u", SignalType::INTEGER, MmsType::MMS_UNSIGNED, {.size = 32 } },
|
||||
Descriptor { "bitstring", SignalType::INTEGER, MmsType::MMS_BIT_STRING, {.size = 32 } },
|
||||
Descriptor { "float32", SignalType::FLOAT, MmsType::MMS_FLOAT, {.size = 32 } },
|
||||
Descriptor { "float64", SignalType::FLOAT, MmsType::MMS_FLOAT, {.size = 64 } },
|
||||
};
|
||||
inline static std::array const descriptors{
|
||||
Descriptor{"boolean", SignalType::BOOLEAN, MmsType::MMS_BOOLEAN},
|
||||
Descriptor{
|
||||
"int8", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 8}},
|
||||
Descriptor{
|
||||
"int16", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 16}},
|
||||
Descriptor{
|
||||
"int32", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 32}},
|
||||
Descriptor{
|
||||
"int64", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 64}},
|
||||
Descriptor{
|
||||
"int8u", SignalType::INTEGER, MmsType::MMS_UNSIGNED, {.size = 8}},
|
||||
Descriptor{
|
||||
"int16u", SignalType::INTEGER, MmsType::MMS_UNSIGNED, {.size = 16}},
|
||||
Descriptor{
|
||||
"int32u", SignalType::INTEGER, MmsType::MMS_UNSIGNED, {.size = 32}},
|
||||
Descriptor{"bitstring",
|
||||
SignalType::INTEGER,
|
||||
MmsType::MMS_BIT_STRING,
|
||||
{.size = 32}},
|
||||
Descriptor{
|
||||
"float32", SignalType::FLOAT, MmsType::MMS_FLOAT, {.size = 32}},
|
||||
Descriptor{
|
||||
"float64", SignalType::FLOAT, MmsType::MMS_FLOAT, {.size = 64}},
|
||||
};
|
||||
|
||||
static
|
||||
MmsValue * newMmsInteger(int64_t i, int size);
|
||||
static MmsValue *newMmsInteger(int64_t i, int size);
|
||||
|
||||
static
|
||||
MmsValue * newMmsUnsigned(uint64_t i, int size);
|
||||
static MmsValue *newMmsUnsigned(uint64_t i, int size);
|
||||
|
||||
static
|
||||
MmsValue * newMmsBitString(uint32_t i, int size);
|
||||
static MmsValue *newMmsBitString(uint32_t i, int size);
|
||||
|
||||
static
|
||||
MmsValue * newMmsFloat(double i, int size);
|
||||
static MmsValue *newMmsFloat(double i, int size);
|
||||
|
||||
// Descriptor within the descriptors table above
|
||||
Descriptor const *descriptor;
|
||||
// Descriptor within the descriptors table above
|
||||
Descriptor const *descriptor;
|
||||
};
|
||||
|
||||
bool operator==(GooseSignal &lhs, GooseSignal &rhs);
|
||||
|
@ -117,141 +124,134 @@ bool operator!=(GooseSignal &lhs, GooseSignal &rhs);
|
|||
|
||||
class GooseNode : public Node {
|
||||
protected:
|
||||
enum InputTrigger {
|
||||
CHANGE,
|
||||
ALWAYS,
|
||||
};
|
||||
enum InputTrigger {
|
||||
CHANGE,
|
||||
ALWAYS,
|
||||
};
|
||||
|
||||
struct InputMapping {
|
||||
std::string subscriber;
|
||||
unsigned int index;
|
||||
GooseSignal::Type type;
|
||||
};
|
||||
struct InputMapping {
|
||||
std::string subscriber;
|
||||
unsigned int index;
|
||||
GooseSignal::Type type;
|
||||
};
|
||||
|
||||
struct SubscriberConfig {
|
||||
std::string go_cb_ref;
|
||||
InputTrigger trigger;
|
||||
std::optional<std::array<uint8_t, 6>> dst_address;
|
||||
std::optional<uint16_t> app_id;
|
||||
};
|
||||
struct SubscriberConfig {
|
||||
std::string go_cb_ref;
|
||||
InputTrigger trigger;
|
||||
std::optional<std::array<uint8_t, 6>> dst_address;
|
||||
std::optional<uint16_t> app_id;
|
||||
};
|
||||
|
||||
struct InputEventContext {
|
||||
SubscriberConfig subscriber_config;
|
||||
struct InputEventContext {
|
||||
SubscriberConfig subscriber_config;
|
||||
|
||||
GooseNode *node;
|
||||
std::vector<std::optional<GooseSignal>> values;
|
||||
int last_state_num;
|
||||
};
|
||||
GooseNode *node;
|
||||
std::vector<std::optional<GooseSignal>> values;
|
||||
int last_state_num;
|
||||
};
|
||||
|
||||
struct Input {
|
||||
enum { NONE, STOPPED, READY } state;
|
||||
GooseReceiver receiver;
|
||||
CQueueSignalled queue;
|
||||
Pool pool;
|
||||
struct Input {
|
||||
enum { NONE, STOPPED, READY } state;
|
||||
GooseReceiver receiver;
|
||||
CQueueSignalled queue;
|
||||
Pool pool;
|
||||
|
||||
std::map<std::string, InputEventContext> contexts;
|
||||
std::vector<InputMapping> mappings;
|
||||
std::string interface_id;
|
||||
bool with_timestamp;
|
||||
unsigned int queue_length;
|
||||
} input;
|
||||
std::map<std::string, InputEventContext> contexts;
|
||||
std::vector<InputMapping> mappings;
|
||||
std::string interface_id;
|
||||
bool with_timestamp;
|
||||
unsigned int queue_length;
|
||||
} input;
|
||||
|
||||
struct OutputData {
|
||||
std::optional<unsigned int> signal;
|
||||
GooseSignal default_value;
|
||||
};
|
||||
struct OutputData {
|
||||
std::optional<unsigned int> signal;
|
||||
GooseSignal default_value;
|
||||
};
|
||||
|
||||
struct PublisherConfig {
|
||||
std::string go_id;
|
||||
std::string go_cb_ref;
|
||||
std::string data_set_ref;
|
||||
std::array<uint8_t, 6> dst_address;
|
||||
uint16_t app_id;
|
||||
uint32_t conf_rev;
|
||||
uint32_t time_allowed_to_live;
|
||||
int burst;
|
||||
std::vector<OutputData> data;
|
||||
};
|
||||
struct PublisherConfig {
|
||||
std::string go_id;
|
||||
std::string go_cb_ref;
|
||||
std::string data_set_ref;
|
||||
std::array<uint8_t, 6> dst_address;
|
||||
uint16_t app_id;
|
||||
uint32_t conf_rev;
|
||||
uint32_t time_allowed_to_live;
|
||||
int burst;
|
||||
std::vector<OutputData> data;
|
||||
};
|
||||
|
||||
struct OutputContext {
|
||||
PublisherConfig config;
|
||||
std::vector<GooseSignal> values;
|
||||
struct OutputContext {
|
||||
PublisherConfig config;
|
||||
std::vector<GooseSignal> values;
|
||||
|
||||
GoosePublisher publisher;
|
||||
};
|
||||
GoosePublisher publisher;
|
||||
};
|
||||
|
||||
struct Output {
|
||||
enum { NONE, STOPPED, READY } state;
|
||||
std::vector<OutputContext> contexts;
|
||||
std::string interface_id;
|
||||
double resend_interval;
|
||||
struct Output {
|
||||
enum { NONE, STOPPED, READY } state;
|
||||
std::vector<OutputContext> contexts;
|
||||
std::string interface_id;
|
||||
double resend_interval;
|
||||
|
||||
std::mutex send_mutex;
|
||||
bool changed;
|
||||
bool resend_thread_stop;
|
||||
std::optional<std::thread> resend_thread;
|
||||
std::condition_variable resend_thread_cv;
|
||||
} output;
|
||||
std::mutex send_mutex;
|
||||
bool changed;
|
||||
bool resend_thread_stop;
|
||||
std::optional<std::thread> resend_thread;
|
||||
std::condition_variable resend_thread_cv;
|
||||
} output;
|
||||
|
||||
void createReceiver() noexcept;
|
||||
void destroyReceiver() noexcept;
|
||||
void createReceiver() noexcept;
|
||||
void destroyReceiver() noexcept;
|
||||
|
||||
void startReceiver() noexcept(false);
|
||||
void stopReceiver() noexcept;
|
||||
void startReceiver() noexcept(false);
|
||||
void stopReceiver() noexcept;
|
||||
|
||||
void createPublishers() noexcept;
|
||||
void destroyPublishers() noexcept;
|
||||
void createPublishers() noexcept;
|
||||
void destroyPublishers() noexcept;
|
||||
|
||||
void startPublishers() noexcept(false);
|
||||
void stopPublishers() noexcept;
|
||||
void startPublishers() noexcept(false);
|
||||
void stopPublishers() noexcept;
|
||||
|
||||
static
|
||||
void onEvent(GooseSubscriber subscriber, InputEventContext &context) noexcept;
|
||||
static void onEvent(GooseSubscriber subscriber,
|
||||
InputEventContext &context) noexcept;
|
||||
|
||||
void addSubscriber(InputEventContext &ctx) noexcept;
|
||||
void pushSample(uint64_t timestamp) noexcept;
|
||||
void addSubscriber(InputEventContext &ctx) noexcept;
|
||||
void pushSample(uint64_t timestamp) noexcept;
|
||||
|
||||
static
|
||||
void publish_values(GoosePublisher publisher, std::vector<GooseSignal> &values, bool changed, int burst = 1) noexcept;
|
||||
static
|
||||
void resend_thread(GooseNode::Output *output) noexcept;
|
||||
static void publish_values(GoosePublisher publisher,
|
||||
std::vector<GooseSignal> &values, bool changed,
|
||||
int burst = 1) noexcept;
|
||||
static void resend_thread(GooseNode::Output *output) noexcept;
|
||||
|
||||
void parseInput(json_t *json);
|
||||
void parseSubscriber(json_t *json, SubscriberConfig &sc);
|
||||
void parseSubscribers(json_t *json, std::map<std::string, InputEventContext> &ctx);
|
||||
void parseInputSignals(json_t *json, std::vector<InputMapping> &mappings);
|
||||
void parseInput(json_t *json);
|
||||
void parseSubscriber(json_t *json, SubscriberConfig &sc);
|
||||
void parseSubscribers(json_t *json,
|
||||
std::map<std::string, InputEventContext> &ctx);
|
||||
void parseInputSignals(json_t *json, std::vector<InputMapping> &mappings);
|
||||
|
||||
void parseOutput(json_t *json);
|
||||
void parsePublisherData(json_t *json, std::vector<OutputData> &data);
|
||||
void parsePublisher(json_t *json, PublisherConfig &pc);
|
||||
void parsePublishers(json_t *json, std::vector<OutputContext> &ctx);
|
||||
void parseOutput(json_t *json);
|
||||
void parsePublisherData(json_t *json, std::vector<OutputData> &data);
|
||||
void parsePublisher(json_t *json, PublisherConfig &pc);
|
||||
void parsePublishers(json_t *json, std::vector<OutputContext> &ctx);
|
||||
|
||||
virtual
|
||||
int _read(struct Sample *smps[], unsigned cnt) override;
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt) override;
|
||||
|
||||
virtual
|
||||
int _write(struct Sample *smps[], unsigned cnt) override;
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt) override;
|
||||
|
||||
public:
|
||||
GooseNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
GooseNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
virtual
|
||||
~GooseNode() override;
|
||||
virtual ~GooseNode() override;
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs() override;
|
||||
virtual std::vector<int> getPollFDs() override;
|
||||
|
||||
virtual
|
||||
int parse(json_t *json) override;
|
||||
virtual int parse(json_t *json) override;
|
||||
|
||||
virtual
|
||||
int prepare() override;
|
||||
virtual int prepare() override;
|
||||
|
||||
virtual
|
||||
int start() override;
|
||||
virtual int start() override;
|
||||
|
||||
virtual
|
||||
int stop() override;
|
||||
virtual int stop() override;
|
||||
};
|
||||
|
||||
} // namespace iec61850
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
#include <libiec61850/sv_publisher.h>
|
||||
#include <libiec61850/sv_subscriber.h>
|
||||
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/nodes/iec61850.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -24,47 +24,47 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
struct iec61850_sv {
|
||||
char *interface;
|
||||
int app_id;
|
||||
struct ether_addr dst_address;
|
||||
char *interface;
|
||||
int app_id;
|
||||
struct ether_addr dst_address;
|
||||
|
||||
struct {
|
||||
bool enabled;
|
||||
struct {
|
||||
bool enabled;
|
||||
|
||||
SVSubscriber subscriber;
|
||||
SVReceiver receiver;
|
||||
SVSubscriber subscriber;
|
||||
SVReceiver receiver;
|
||||
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
|
||||
struct List signals; // Mappings of type struct iec61850_type_descriptor
|
||||
int total_size;
|
||||
} in;
|
||||
struct List signals; // Mappings of type struct iec61850_type_descriptor
|
||||
int total_size;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
bool enabled;
|
||||
struct {
|
||||
bool enabled;
|
||||
|
||||
SVPublisher publisher;
|
||||
SVPublisher_ASDU asdu;
|
||||
SVPublisher publisher;
|
||||
SVPublisher_ASDU asdu;
|
||||
|
||||
char *svid;
|
||||
char *svid;
|
||||
|
||||
int vlan_priority;
|
||||
int vlan_id;
|
||||
int smpmod;
|
||||
int smprate;
|
||||
int confrev;
|
||||
int vlan_priority;
|
||||
int vlan_id;
|
||||
int smpmod;
|
||||
int smprate;
|
||||
int confrev;
|
||||
|
||||
struct List signals; // Mappings of type struct iec61850_type_descriptor
|
||||
int total_size;
|
||||
} out;
|
||||
struct List signals; // Mappings of type struct iec61850_type_descriptor
|
||||
int total_size;
|
||||
} out;
|
||||
};
|
||||
|
||||
int iec61850_sv_type_stop();
|
||||
|
||||
int iec61850_sv_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
char * iec61850_sv_print(NodeCompat *n);
|
||||
char *iec61850_sv_print(NodeCompat *n);
|
||||
|
||||
int iec61850_sv_start(NodeCompat *n);
|
||||
|
||||
|
@ -72,9 +72,9 @@ int iec61850_sv_stop(NodeCompat *n);
|
|||
|
||||
int iec61850_sv_destroy(NodeCompat *n);
|
||||
|
||||
int iec61850_sv_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int iec61850_sv_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int iec61850_sv_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int iec61850_sv_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int iec61850_sv_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <rdma/rdma_cma.h>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -25,76 +25,76 @@ class NodeCompat;
|
|||
#define CHK_PER_ITER 2048
|
||||
|
||||
struct infiniband {
|
||||
// IBV/RDMA CM structs
|
||||
struct context_s {
|
||||
struct rdma_cm_id *listen_id;
|
||||
struct rdma_cm_id *id;
|
||||
struct rdma_event_channel *ec;
|
||||
// IBV/RDMA CM structs
|
||||
struct context_s {
|
||||
struct rdma_cm_id *listen_id;
|
||||
struct rdma_cm_id *id;
|
||||
struct rdma_event_channel *ec;
|
||||
|
||||
struct ibv_pd *pd;
|
||||
struct ibv_cq *recv_cq;
|
||||
struct ibv_cq *send_cq;
|
||||
struct ibv_comp_channel *comp_channel;
|
||||
} ctx;
|
||||
struct ibv_pd *pd;
|
||||
struct ibv_cq *recv_cq;
|
||||
struct ibv_cq *send_cq;
|
||||
struct ibv_comp_channel *comp_channel;
|
||||
} ctx;
|
||||
|
||||
// Queue Pair init variables
|
||||
struct ibv_qp_init_attr qp_init;
|
||||
// Queue Pair init variables
|
||||
struct ibv_qp_init_attr qp_init;
|
||||
|
||||
// Size of receive and send completion queue
|
||||
int recv_cq_size;
|
||||
int send_cq_size;
|
||||
// Size of receive and send completion queue
|
||||
int recv_cq_size;
|
||||
int send_cq_size;
|
||||
|
||||
// Bool, set if threads should be aborted
|
||||
int stopThreads;
|
||||
// Bool, set if threads should be aborted
|
||||
int stopThreads;
|
||||
|
||||
// When most messages are sent inline, once every <X> cycles a signal must be sent.
|
||||
unsigned signaling_counter;
|
||||
unsigned periodic_signaling;
|
||||
// When most messages are sent inline, once every <X> cycles a signal must be sent.
|
||||
unsigned signaling_counter;
|
||||
unsigned periodic_signaling;
|
||||
|
||||
// Connection specific variables
|
||||
struct connection_s {
|
||||
struct addrinfo *src_addr;
|
||||
struct addrinfo *dst_addr;
|
||||
// Connection specific variables
|
||||
struct connection_s {
|
||||
struct addrinfo *src_addr;
|
||||
struct addrinfo *dst_addr;
|
||||
|
||||
// RDMA_PS_TCP or RDMA_PS_UDP
|
||||
enum rdma_port_space port_space;
|
||||
// RDMA_PS_TCP or RDMA_PS_UDP
|
||||
enum rdma_port_space port_space;
|
||||
|
||||
// Timeout for rdma_resolve_route
|
||||
int timeout;
|
||||
// Timeout for rdma_resolve_route
|
||||
int timeout;
|
||||
|
||||
// Thread to monitor RDMA CM Event threads
|
||||
pthread_t rdma_cm_event_thread;
|
||||
// Thread to monitor RDMA CM Event threads
|
||||
pthread_t rdma_cm_event_thread;
|
||||
|
||||
// Bool, should data be send inline if possible?
|
||||
int send_inline;
|
||||
// Bool, should data be send inline if possible?
|
||||
int send_inline;
|
||||
|
||||
// Bool, should node have a fallback if it can't connect to a remote host?
|
||||
int use_fallback;
|
||||
// Bool, should node have a fallback if it can't connect to a remote host?
|
||||
int use_fallback;
|
||||
|
||||
// Counter to keep track of available recv. WRs
|
||||
unsigned available_recv_wrs;
|
||||
// Counter to keep track of available recv. WRs
|
||||
unsigned available_recv_wrs;
|
||||
|
||||
/* Fixed number to substract from min. number available
|
||||
/* Fixed number to substract from min. number available
|
||||
* WRs in receive queue */
|
||||
unsigned buffer_subtraction;
|
||||
unsigned buffer_subtraction;
|
||||
|
||||
// Unrealiable connectionless data
|
||||
struct ud_s {
|
||||
struct rdma_ud_param ud;
|
||||
struct ibv_ah *ah;
|
||||
void *grh_ptr;
|
||||
struct ibv_mr *grh_mr;
|
||||
} ud;
|
||||
// Unrealiable connectionless data
|
||||
struct ud_s {
|
||||
struct rdma_ud_param ud;
|
||||
struct ibv_ah *ah;
|
||||
void *grh_ptr;
|
||||
struct ibv_mr *grh_mr;
|
||||
} ud;
|
||||
|
||||
} conn;
|
||||
} conn;
|
||||
|
||||
// Misc settings
|
||||
int is_source;
|
||||
// Misc settings
|
||||
int is_source;
|
||||
};
|
||||
|
||||
int ib_reverse(NodeCompat *n);
|
||||
|
||||
char * ib_print(NodeCompat *n);
|
||||
char *ib_print(NodeCompat *n);
|
||||
|
||||
int ib_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
|
@ -106,9 +106,9 @@ int ib_destroy(NodeCompat *n);
|
|||
|
||||
int ib_stop(NodeCompat *n);
|
||||
|
||||
int ib_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int ib_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int ib_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int ib_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -17,16 +17,16 @@ class NodeCompat;
|
|||
struct Sample;
|
||||
|
||||
struct influxdb {
|
||||
char *host;
|
||||
char *port;
|
||||
char *key;
|
||||
char *host;
|
||||
char *port;
|
||||
char *key;
|
||||
|
||||
struct List fields;
|
||||
struct List fields;
|
||||
|
||||
int sd;
|
||||
int sd;
|
||||
};
|
||||
|
||||
char * influxdb_print(NodeCompat *n);
|
||||
char *influxdb_print(NodeCompat *n);
|
||||
|
||||
int influxdb_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
|
@ -34,7 +34,7 @@ int influxdb_open(NodeCompat *n);
|
|||
|
||||
int influxdb_close(NodeCompat *n);
|
||||
|
||||
int influxdb_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int influxdb_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
#include <librdkafka/rdkafka.h>
|
||||
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
|
||||
namespace villas {
|
||||
|
@ -20,42 +20,42 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
struct kafka {
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
|
||||
double timeout; // Timeout in seconds.
|
||||
char *server; // Hostname/IP:Port address of the bootstrap server.
|
||||
char *protocol; // Security protocol.
|
||||
char *produce; // Producer topic.
|
||||
char *consume; // Consumer topic.
|
||||
char *client_id; // Client ID.
|
||||
double timeout; // Timeout in seconds.
|
||||
char *server; // Hostname/IP:Port address of the bootstrap server.
|
||||
char *protocol; // Security protocol.
|
||||
char *produce; // Producer topic.
|
||||
char *consume; // Consumer topic.
|
||||
char *client_id; // Client ID.
|
||||
|
||||
struct {
|
||||
rd_kafka_t *client;
|
||||
rd_kafka_topic_t *topic;
|
||||
} producer;
|
||||
struct {
|
||||
rd_kafka_t *client;
|
||||
rd_kafka_topic_t *topic;
|
||||
} producer;
|
||||
|
||||
struct {
|
||||
rd_kafka_t *client;
|
||||
char *group_id; // Group id.
|
||||
} consumer;
|
||||
struct {
|
||||
rd_kafka_t *client;
|
||||
char *group_id; // Group id.
|
||||
} consumer;
|
||||
|
||||
struct {
|
||||
char *ca; // SSL CA file.
|
||||
} ssl;
|
||||
struct {
|
||||
char *ca; // SSL CA file.
|
||||
} ssl;
|
||||
|
||||
struct {
|
||||
char *mechanisms; // SASL mechanisms.
|
||||
char *username; // SSL CA path.
|
||||
char *password; // SSL certificate.
|
||||
} sasl;
|
||||
struct {
|
||||
char *mechanisms; // SASL mechanisms.
|
||||
char *username; // SSL CA path.
|
||||
char *password; // SSL certificate.
|
||||
} sasl;
|
||||
|
||||
Format *formatter;
|
||||
Format *formatter;
|
||||
};
|
||||
|
||||
int kafka_reverse(NodeCompat *n);
|
||||
|
||||
char * kafka_print(NodeCompat *n);
|
||||
char *kafka_print(NodeCompat *n);
|
||||
|
||||
int kafka_init(NodeCompat *n);
|
||||
|
||||
|
@ -75,9 +75,9 @@ int kafka_type_stop();
|
|||
|
||||
int kafka_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
int kafka_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int kafka_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int kafka_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int kafka_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -17,36 +17,28 @@ namespace node {
|
|||
class LoopbackNode : public Node {
|
||||
|
||||
protected:
|
||||
int queuelen;
|
||||
struct CQueueSignalled queue;
|
||||
enum QueueSignalledMode mode;
|
||||
int queuelen;
|
||||
struct CQueueSignalled queue;
|
||||
enum QueueSignalledMode mode;
|
||||
|
||||
virtual
|
||||
int _write(struct Sample * smps[], unsigned cnt);
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int _read(struct Sample * smps[], unsigned cnt);
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
LoopbackNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
LoopbackNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
virtual
|
||||
~LoopbackNode();
|
||||
virtual ~LoopbackNode();
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
virtual int prepare();
|
||||
|
||||
virtual
|
||||
int stop();
|
||||
virtual int stop();
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs();
|
||||
virtual std::vector<int> getPollFDs();
|
||||
|
||||
virtual
|
||||
const std::string & getDetails();
|
||||
virtual const std::string &getDetails();
|
||||
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -16,62 +16,48 @@ namespace node {
|
|||
class InternalLoopbackNode : public Node {
|
||||
|
||||
protected:
|
||||
unsigned queuelen;
|
||||
struct CQueueSignalled queue;
|
||||
unsigned queuelen;
|
||||
struct CQueueSignalled queue;
|
||||
|
||||
Node *source;
|
||||
Node *source;
|
||||
|
||||
virtual
|
||||
int _write(struct Sample * smps[], unsigned cnt);
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int _read(struct Sample * smps[], unsigned cnt);
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
InternalLoopbackNode(Node *src, unsigned id = 0, unsigned ql = DEFAULT_QUEUE_LENGTH);
|
||||
InternalLoopbackNode(Node *src, unsigned id = 0,
|
||||
unsigned ql = DEFAULT_QUEUE_LENGTH);
|
||||
|
||||
virtual
|
||||
~InternalLoopbackNode();
|
||||
virtual ~InternalLoopbackNode();
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs();
|
||||
virtual std::vector<int> getPollFDs();
|
||||
|
||||
virtual
|
||||
int stop();
|
||||
virtual int stop();
|
||||
};
|
||||
|
||||
class InternalLoopbackNodeFactory : public NodeFactory {
|
||||
|
||||
public:
|
||||
using NodeFactory::NodeFactory;
|
||||
using NodeFactory::NodeFactory;
|
||||
|
||||
virtual
|
||||
Node * make(const uuid_t &id = {}, const std::string &name = "")
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual Node *make(const uuid_t &id = {}, const std::string &name = "") {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual
|
||||
int getFlags() const
|
||||
{
|
||||
return (int) NodeFactory::Flags::INTERNAL |
|
||||
(int) NodeFactory::Flags::PROVIDES_SIGNALS |
|
||||
(int) NodeFactory::Flags::SUPPORTS_READ |
|
||||
(int) NodeFactory::Flags::SUPPORTS_WRITE |
|
||||
(int) NodeFactory::Flags::SUPPORTS_POLL;
|
||||
}
|
||||
virtual int getFlags() const {
|
||||
return (int)NodeFactory::Flags::INTERNAL |
|
||||
(int)NodeFactory::Flags::PROVIDES_SIGNALS |
|
||||
(int)NodeFactory::Flags::SUPPORTS_READ |
|
||||
(int)NodeFactory::Flags::SUPPORTS_WRITE |
|
||||
(int)NodeFactory::Flags::SUPPORTS_POLL;
|
||||
}
|
||||
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return "loopback.internal";
|
||||
}
|
||||
virtual std::string getName() const { return "loopback.internal"; }
|
||||
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return "internal loopback node";
|
||||
}
|
||||
virtual std::string getDescription() const {
|
||||
return "internal loopback node";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,22 +7,22 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <bit>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <modbus/modbus.h>
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
#include <villas/sample.hpp>
|
||||
#include <villas/exceptions.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/sample.hpp>
|
||||
#include <villas/task.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -32,37 +32,35 @@ using modbus_addr_t = uint16_t;
|
|||
using modbus_addrdiff_t = int32_t;
|
||||
|
||||
enum class Parity : char {
|
||||
None = 'N',
|
||||
Even = 'E',
|
||||
Odd = 'O',
|
||||
None = 'N',
|
||||
Even = 'E',
|
||||
Odd = 'O',
|
||||
};
|
||||
|
||||
enum class Endianess : char {
|
||||
Big,
|
||||
Little,
|
||||
Big,
|
||||
Little,
|
||||
};
|
||||
|
||||
// The settings for an RTU modbus connection.
|
||||
struct Rtu {
|
||||
std::string device;
|
||||
Parity parity;
|
||||
int baudrate;
|
||||
int data_bits;
|
||||
int stop_bits;
|
||||
unsigned char unit;
|
||||
std::string device;
|
||||
Parity parity;
|
||||
int baudrate;
|
||||
int data_bits;
|
||||
int stop_bits;
|
||||
unsigned char unit;
|
||||
|
||||
static
|
||||
Rtu parse(json_t *json);
|
||||
static Rtu parse(json_t *json);
|
||||
};
|
||||
|
||||
// The settings for an TCP MODBUS connection.
|
||||
struct Tcp {
|
||||
std::string remote;
|
||||
uint16_t port;
|
||||
std::optional<unsigned char> unit;
|
||||
std::string remote;
|
||||
uint16_t port;
|
||||
std::optional<unsigned char> unit;
|
||||
|
||||
static
|
||||
Tcp parse(json_t *json);
|
||||
static Tcp parse(json_t *json);
|
||||
};
|
||||
|
||||
// Forward declarations
|
||||
|
@ -72,7 +70,8 @@ class RegisterMappingSingle;
|
|||
using RegisterMappingBlock = std::vector<RegisterMappingSingle>;
|
||||
|
||||
// Either a single mapping or a merged block of mappings.
|
||||
using RegisterMapping = std::variant<RegisterMappingSingle, RegisterMappingBlock>;
|
||||
using RegisterMapping =
|
||||
std::variant<RegisterMappingSingle, RegisterMappingBlock>;
|
||||
|
||||
// Swap the two bytes of a 16 bit integer.
|
||||
uint16_t byteswap(uint16_t i);
|
||||
|
@ -105,13 +104,16 @@ modbus_addr_t mappedRegisters(RegisterMappingBlock const &block);
|
|||
modbus_addr_t mappedRegisters(RegisterMapping const &mapping);
|
||||
|
||||
// The distance between two blocks.
|
||||
modbus_addrdiff_t blockDistance(RegisterMapping const &lhs, RegisterMapping const &rhs);
|
||||
modbus_addrdiff_t blockDistance(RegisterMapping const &lhs,
|
||||
RegisterMapping const &rhs);
|
||||
|
||||
// Whether there are overlapping bit mappings between lhs and rhs.
|
||||
bool hasOverlappingBitMapping(RegisterMapping const &lhs, RegisterMapping const &rhs);
|
||||
bool hasOverlappingBitMapping(RegisterMapping const &lhs,
|
||||
RegisterMapping const &rhs);
|
||||
|
||||
// The compare the addresses of two mappings.
|
||||
bool compareBlockAddress(RegisterMapping const &lhs, RegisterMapping const &rhs);
|
||||
bool compareBlockAddress(RegisterMapping const &lhs,
|
||||
RegisterMapping const &rhs);
|
||||
|
||||
// Parse an Endianess from a null terminated string.
|
||||
Endianess parseEndianess(char const *str);
|
||||
|
@ -122,170 +124,176 @@ Parity parseParity(char const *str);
|
|||
// The mapping from a register to a signal.
|
||||
class RegisterMappingSingle {
|
||||
public:
|
||||
inline static constexpr
|
||||
size_t MAX_REGISTERS = sizeof(int64_t) / sizeof(int16_t);
|
||||
inline static constexpr size_t MAX_REGISTERS =
|
||||
sizeof(int64_t) / sizeof(int16_t);
|
||||
|
||||
struct IntegerToInteger {
|
||||
Endianess word_endianess;
|
||||
Endianess byte_endianess;
|
||||
modbus_addr_t num_registers;
|
||||
struct IntegerToInteger {
|
||||
Endianess word_endianess;
|
||||
Endianess byte_endianess;
|
||||
modbus_addr_t num_registers;
|
||||
|
||||
int64_t read(uint16_t const *registers) const;
|
||||
void write(int64_t i, uint16_t *registers) const;
|
||||
};
|
||||
int64_t read(uint16_t const *registers) const;
|
||||
void write(int64_t i, uint16_t *registers) const;
|
||||
};
|
||||
|
||||
struct IntegerToFloat {
|
||||
IntegerToInteger integer_conversion;
|
||||
double offset;
|
||||
double scale;
|
||||
struct IntegerToFloat {
|
||||
IntegerToInteger integer_conversion;
|
||||
double offset;
|
||||
double scale;
|
||||
|
||||
double read(uint16_t const *registers) const;
|
||||
void write(double d, uint16_t *registers) const;
|
||||
};
|
||||
double read(uint16_t const *registers) const;
|
||||
void write(double d, uint16_t *registers) const;
|
||||
};
|
||||
|
||||
struct FloatToFloat {
|
||||
Endianess word_endianess;
|
||||
Endianess byte_endianess;
|
||||
double offset;
|
||||
double scale;
|
||||
struct FloatToFloat {
|
||||
Endianess word_endianess;
|
||||
Endianess byte_endianess;
|
||||
double offset;
|
||||
double scale;
|
||||
|
||||
double read(uint16_t const *registers) const;
|
||||
void write(double d, uint16_t *registers) const;
|
||||
};
|
||||
double read(uint16_t const *registers) const;
|
||||
void write(double d, uint16_t *registers) const;
|
||||
};
|
||||
|
||||
struct BitToBool {
|
||||
uint8_t bit;
|
||||
struct BitToBool {
|
||||
uint8_t bit;
|
||||
|
||||
bool read(uint16_t reg) const;
|
||||
};
|
||||
bool read(uint16_t reg) const;
|
||||
};
|
||||
|
||||
// Conversion rule for registers.
|
||||
//
|
||||
// - IntegerToInteger means merging multiple registers.
|
||||
// - FloatToFloat converts from IEEE float to float.
|
||||
// - IntegerToFloat converts registers to integer, casts to float
|
||||
// and then applies offset and scale to produce a float.
|
||||
// - BitToBool takes a single bit from a registers and reports it as a boolean.
|
||||
std::variant<IntegerToInteger, IntegerToFloat, FloatToFloat, BitToBool> conversion;
|
||||
// Conversion rule for registers.
|
||||
//
|
||||
// - IntegerToInteger means merging multiple registers.
|
||||
// - FloatToFloat converts from IEEE float to float.
|
||||
// - IntegerToFloat converts registers to integer, casts to float
|
||||
// and then applies offset and scale to produce a float.
|
||||
// - BitToBool takes a single bit from a registers and reports it as a boolean.
|
||||
std::variant<IntegerToInteger, IntegerToFloat, FloatToFloat, BitToBool>
|
||||
conversion;
|
||||
|
||||
RegisterMappingSingle(unsigned int signal_index, modbus_addr_t address);
|
||||
RegisterMappingSingle(unsigned int signal_index, modbus_addr_t address);
|
||||
|
||||
unsigned int signal_index;
|
||||
modbus_addr_t address;
|
||||
unsigned int signal_index;
|
||||
modbus_addr_t address;
|
||||
|
||||
static
|
||||
RegisterMappingSingle parse(unsigned int index, Signal::Ptr signal, json_t *json);
|
||||
static RegisterMappingSingle parse(unsigned int index, Signal::Ptr signal,
|
||||
json_t *json);
|
||||
|
||||
SignalData read(uint16_t const *registers, modbus_addr_t length) const;
|
||||
void write(SignalData data, uint16_t *registers, modbus_addr_t length) const;
|
||||
SignalData read(uint16_t const *registers, modbus_addr_t length) const;
|
||||
void write(SignalData data, uint16_t *registers, modbus_addr_t length) const;
|
||||
|
||||
modbus_addr_t num_registers() const;
|
||||
modbus_addr_t num_registers() const;
|
||||
};
|
||||
|
||||
class ModbusNode final : public Node {
|
||||
private:
|
||||
// The maximum size of a RegisterMappingBlock created during mergeMappings.
|
||||
// The size of a block here is defined as the difference between blockBegin and blockEnd.
|
||||
modbus_addr_t max_block_size;
|
||||
// The maximum size of a RegisterMappingBlock created during mergeMappings.
|
||||
// The size of a block here is defined as the difference between blockBegin and blockEnd.
|
||||
modbus_addr_t max_block_size;
|
||||
|
||||
// The minimum block usage of a RegisterMappingBlock created during mergeMappings.
|
||||
// The usage of a block is defined as the ration of registers used in mappings to the size of the block.
|
||||
// The size of a block here is defined as the difference between blockBegin and blockEnd.
|
||||
float min_block_usage;
|
||||
// The minimum block usage of a RegisterMappingBlock created during mergeMappings.
|
||||
// The usage of a block is defined as the ration of registers used in mappings to the size of the block.
|
||||
// The size of a block here is defined as the difference between blockBegin and blockEnd.
|
||||
float min_block_usage;
|
||||
|
||||
// The type of connection settings used to initialize the modbus_context.
|
||||
std::variant<std::monostate, Tcp, Rtu> connection_settings;
|
||||
// The type of connection settings used to initialize the modbus_context.
|
||||
std::variant<std::monostate, Tcp, Rtu> connection_settings;
|
||||
|
||||
// The rate used for periodically querying the modbus device registers.
|
||||
double rate;
|
||||
// The rate used for periodically querying the modbus device registers.
|
||||
double rate;
|
||||
|
||||
// The timeout in seconds when waiting for a response from a modbus slave/server.
|
||||
double response_timeout;
|
||||
// The timeout in seconds when waiting for a response from a modbus slave/server.
|
||||
double response_timeout;
|
||||
|
||||
// Mappings used to create the input signals from the read registers.
|
||||
std::vector<RegisterMapping> in_mappings;
|
||||
// Mappings used to create the input signals from the read registers.
|
||||
std::vector<RegisterMapping> in_mappings;
|
||||
|
||||
// Number of in signals.
|
||||
unsigned int num_in_signals;
|
||||
// Number of in signals.
|
||||
unsigned int num_in_signals;
|
||||
|
||||
// Mappings used to create the input signals from the read registers.
|
||||
std::vector<RegisterMapping> out_mappings;
|
||||
// Mappings used to create the input signals from the read registers.
|
||||
std::vector<RegisterMapping> out_mappings;
|
||||
|
||||
// Number of out signals.
|
||||
unsigned int num_out_signals;
|
||||
// Number of out signals.
|
||||
unsigned int num_out_signals;
|
||||
|
||||
// The interval in seconds for trying to reconnect on connection loss.
|
||||
double reconnect_interval;
|
||||
// The interval in seconds for trying to reconnect on connection loss.
|
||||
double reconnect_interval;
|
||||
|
||||
std::vector<uint16_t> read_buffer;
|
||||
std::vector<uint16_t> write_buffer;
|
||||
modbus_t *modbus_context;
|
||||
Task read_task;
|
||||
std::atomic<bool> reconnecting;
|
||||
std::vector<uint16_t> read_buffer;
|
||||
std::vector<uint16_t> write_buffer;
|
||||
modbus_t *modbus_context;
|
||||
Task read_task;
|
||||
std::atomic<bool> reconnecting;
|
||||
|
||||
bool isReconnecting();
|
||||
void reconnect();
|
||||
bool isReconnecting();
|
||||
void reconnect();
|
||||
|
||||
static
|
||||
void mergeMappingInplace(RegisterMapping &lhs, RegisterMappingBlock const &rhs);
|
||||
static void mergeMappingInplace(RegisterMapping &lhs,
|
||||
RegisterMappingBlock const &rhs);
|
||||
|
||||
static
|
||||
void mergeMappingInplace(RegisterMapping &lhs, RegisterMappingSingle const &rhs);
|
||||
static void mergeMappingInplace(RegisterMapping &lhs,
|
||||
RegisterMappingSingle const &rhs);
|
||||
|
||||
bool tryMergeMappingInplace(RegisterMapping &lhs, RegisterMapping const &rhs);
|
||||
bool tryMergeMappingInplace(RegisterMapping &lhs, RegisterMapping const &rhs);
|
||||
|
||||
void mergeMappings(std::vector<RegisterMapping> &mappings, modbus_addrdiff_t max_block_distance);
|
||||
void mergeMappings(std::vector<RegisterMapping> &mappings,
|
||||
modbus_addrdiff_t max_block_distance);
|
||||
|
||||
unsigned int parseMappings(std::vector<RegisterMapping> &mappings, json_t *json);
|
||||
unsigned int parseMappings(std::vector<RegisterMapping> &mappings,
|
||||
json_t *json);
|
||||
|
||||
int readMapping(RegisterMappingSingle const &mapping, uint16_t const *registers, modbus_addr_t num_registers, SignalData *signals, unsigned int num_signals);
|
||||
int readMapping(RegisterMappingSingle const &mapping,
|
||||
uint16_t const *registers, modbus_addr_t num_registers,
|
||||
SignalData *signals, unsigned int num_signals);
|
||||
|
||||
int readMapping(RegisterMappingBlock const &mapping, uint16_t const *registers, modbus_addr_t num_registers, SignalData *signals, unsigned int num_signals);
|
||||
int readMapping(RegisterMappingBlock const &mapping,
|
||||
uint16_t const *registers, modbus_addr_t num_registers,
|
||||
SignalData *signals, unsigned int num_signals);
|
||||
|
||||
int readMapping(RegisterMapping const &mapping, uint16_t const *registers, modbus_addr_t num_registers, SignalData *signals, unsigned int num_signals);
|
||||
int readMapping(RegisterMapping const &mapping, uint16_t const *registers,
|
||||
modbus_addr_t num_registers, SignalData *signals,
|
||||
unsigned int num_signals);
|
||||
|
||||
int readBlock(RegisterMapping const &mapping, SignalData *signals, size_t num_signals);
|
||||
int readBlock(RegisterMapping const &mapping, SignalData *signals,
|
||||
size_t num_signals);
|
||||
|
||||
virtual
|
||||
int _read(struct Sample *smps[], unsigned int cnt);
|
||||
virtual int _read(struct Sample *smps[], unsigned int cnt);
|
||||
|
||||
int writeMapping(RegisterMappingSingle const &mapping, uint16_t *registers, modbus_addr_t num_registers, SignalData const *signals, unsigned int num_signals);
|
||||
int writeMapping(RegisterMappingBlock const &mapping, uint16_t *registers, modbus_addr_t num_registers, SignalData const *signals, unsigned int num_signals);
|
||||
int writeMapping(RegisterMapping const &mapping, uint16_t *registers, modbus_addr_t num_registers, SignalData const *signals, unsigned int num_signals);
|
||||
int writeBlock(RegisterMapping const &mapping, SignalData const *signals, size_t num_signals);
|
||||
int writeMapping(RegisterMappingSingle const &mapping, uint16_t *registers,
|
||||
modbus_addr_t num_registers, SignalData const *signals,
|
||||
unsigned int num_signals);
|
||||
int writeMapping(RegisterMappingBlock const &mapping, uint16_t *registers,
|
||||
modbus_addr_t num_registers, SignalData const *signals,
|
||||
unsigned int num_signals);
|
||||
int writeMapping(RegisterMapping const &mapping, uint16_t *registers,
|
||||
modbus_addr_t num_registers, SignalData const *signals,
|
||||
unsigned int num_signals);
|
||||
int writeBlock(RegisterMapping const &mapping, SignalData const *signals,
|
||||
size_t num_signals);
|
||||
|
||||
virtual
|
||||
int _write(struct Sample *smps[], unsigned int cnt);
|
||||
virtual int _write(struct Sample *smps[], unsigned int cnt);
|
||||
|
||||
public:
|
||||
ModbusNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
ModbusNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
virtual
|
||||
~ModbusNode();
|
||||
virtual ~ModbusNode();
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
virtual int prepare();
|
||||
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
virtual
|
||||
int check();
|
||||
virtual int check();
|
||||
|
||||
virtual
|
||||
int start();
|
||||
virtual int start();
|
||||
|
||||
virtual
|
||||
int stop();
|
||||
virtual int stop();
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs();
|
||||
virtual std::vector<int> getPollFDs();
|
||||
|
||||
virtual
|
||||
std::vector<int> getNetemFDs();
|
||||
virtual std::vector<int> getNetemFDs();
|
||||
|
||||
virtual
|
||||
const std::string & getDetails();
|
||||
virtual const std::string &getDetails();
|
||||
};
|
||||
|
||||
} // namespace modbus
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <villas/super_node.hpp>
|
||||
|
||||
|
@ -22,38 +22,38 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
struct mqtt {
|
||||
struct mosquitto *client;
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
struct mosquitto *client;
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
|
||||
int keepalive; // Keep-alive interval in seconds. Zero for no keepalive.
|
||||
int port; // Hostname / IP address of the broker.
|
||||
int qos; // Integer value 0, 1 or 2 indicating the Quality of Service to be used for publishing messages.
|
||||
int retain; // Mark published messages as retained.
|
||||
char *host; // Hostname / IP address of the broker.
|
||||
char *username; // Username for authentication to the broker.
|
||||
char *password; // Password for authentication to the broker.
|
||||
char *publish; // Publish topic.
|
||||
char *subscribe; // Subscribe topic.
|
||||
int keepalive; // Keep-alive interval in seconds. Zero for no keepalive.
|
||||
int port; // Hostname / IP address of the broker.
|
||||
int qos; // Integer value 0, 1 or 2 indicating the Quality of Service to be used for publishing messages.
|
||||
int retain; // Mark published messages as retained.
|
||||
char *host; // Hostname / IP address of the broker.
|
||||
char *username; // Username for authentication to the broker.
|
||||
char *password; // Password for authentication to the broker.
|
||||
char *publish; // Publish topic.
|
||||
char *subscribe; // Subscribe topic.
|
||||
|
||||
struct {
|
||||
int enabled; // Enable SSL encrypted connection to broker.
|
||||
int insecure; // Allow insecure SSL connections.
|
||||
char *cafile; // SSL CA file.
|
||||
char *capath; // SSL CA path.
|
||||
char *certfile; // SSL certificate.
|
||||
char *keyfile; // SSL private key.
|
||||
int cert_reqs; // SSL_VERIFY_NONE(0) or SSL_VERIFY_PEER(1)
|
||||
char *tls_version; // SSL tls verion
|
||||
char *ciphers; // SSL chipher list.
|
||||
} ssl;
|
||||
struct {
|
||||
int enabled; // Enable SSL encrypted connection to broker.
|
||||
int insecure; // Allow insecure SSL connections.
|
||||
char *cafile; // SSL CA file.
|
||||
char *capath; // SSL CA path.
|
||||
char *certfile; // SSL certificate.
|
||||
char *keyfile; // SSL private key.
|
||||
int cert_reqs; // SSL_VERIFY_NONE(0) or SSL_VERIFY_PEER(1)
|
||||
char *tls_version; // SSL tls verion
|
||||
char *ciphers; // SSL chipher list.
|
||||
} ssl;
|
||||
|
||||
Format *formatter;
|
||||
Format *formatter;
|
||||
};
|
||||
|
||||
int mqtt_reverse(NodeCompat *n);
|
||||
|
||||
char * mqtt_print(NodeCompat *n);
|
||||
char *mqtt_print(NodeCompat *n);
|
||||
|
||||
int mqtt_prepare(NodeCompat *n);
|
||||
|
||||
|
@ -75,9 +75,9 @@ int mqtt_type_stop();
|
|||
|
||||
int mqtt_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
int mqtt_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int mqtt_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int mqtt_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int mqtt_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/list.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -20,15 +20,15 @@ class NodeCompat;
|
|||
#define NANOMSG_MAX_PACKET_LEN 1500
|
||||
|
||||
struct nanomsg {
|
||||
struct {
|
||||
int socket;
|
||||
struct List endpoints;
|
||||
} in, out;
|
||||
struct {
|
||||
int socket;
|
||||
struct List endpoints;
|
||||
} in, out;
|
||||
|
||||
Format *formatter;
|
||||
Format *formatter;
|
||||
};
|
||||
|
||||
char * nanomsg_print(NodeCompat *n);
|
||||
char *nanomsg_print(NodeCompat *n);
|
||||
|
||||
int nanomsg_init(NodeCompat *n);
|
||||
|
||||
|
@ -48,9 +48,9 @@ int nanomsg_poll_fds(NodeCompat *n, int fds[]);
|
|||
|
||||
int nanomsg_netem_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
int nanomsg_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int nanomsg_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int nanomsg_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int nanomsg_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -26,26 +26,28 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
struct ngsi {
|
||||
const char *endpoint; // The NGSI context broker endpoint URL.
|
||||
const char *entity_id; // The context broker entity id related to this node
|
||||
const char *entity_type; // The type of the entity
|
||||
const char *access_token; // An optional authentication token which will be sent as HTTP header.
|
||||
const char *endpoint; // The NGSI context broker endpoint URL.
|
||||
const char *entity_id; // The context broker entity id related to this node
|
||||
const char *entity_type; // The type of the entity
|
||||
const char *
|
||||
access_token; // An optional authentication token which will be sent as HTTP header.
|
||||
|
||||
bool create; // Weather we want to create the context element during startup.
|
||||
bool remove; // Weather we want to delete the context element during startup.
|
||||
bool create; // Weather we want to create the context element during startup.
|
||||
bool remove; // Weather we want to delete the context element during startup.
|
||||
|
||||
double timeout; // HTTP timeout in seconds
|
||||
double rate; // Rate used for polling.
|
||||
double timeout; // HTTP timeout in seconds
|
||||
double rate; // Rate used for polling.
|
||||
|
||||
struct Task task; // Timer for periodic events.
|
||||
int ssl_verify; // Boolean flag whether SSL server certificates should be verified or not.
|
||||
struct Task task; // Timer for periodic events.
|
||||
int ssl_verify; // Boolean flag whether SSL server certificates should be verified or not.
|
||||
|
||||
struct curl_slist *headers; // List of HTTP request headers for libcurl
|
||||
struct curl_slist *headers; // List of HTTP request headers for libcurl
|
||||
|
||||
struct {
|
||||
CURL *curl; // libcurl: handle
|
||||
struct List signals; // A mapping between indices of the VILLASnode samples and the attributes in ngsi::context
|
||||
} in, out;
|
||||
struct {
|
||||
CURL *curl; // libcurl: handle
|
||||
struct List
|
||||
signals; // A mapping between indices of the VILLASnode samples and the attributes in ngsi::context
|
||||
} in, out;
|
||||
};
|
||||
|
||||
int ngsi_type_start(SuperNode *sn);
|
||||
|
@ -54,7 +56,7 @@ int ngsi_type_stop();
|
|||
|
||||
int ngsi_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
char * ngsi_print(NodeCompat *n);
|
||||
char *ngsi_print(NodeCompat *n);
|
||||
|
||||
int ngsi_init(NodeCompat *n);
|
||||
|
||||
|
@ -66,9 +68,9 @@ int ngsi_stop(NodeCompat *n);
|
|||
|
||||
int ngsi_reverse(NodeCompat *n);
|
||||
|
||||
int ngsi_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int ngsi_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int ngsi_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int ngsi_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int ngsi_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
|
|
|
@ -18,19 +18,19 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
extern "C" {
|
||||
#include <OpalGenAsyncParamCtrl.h>
|
||||
#include <OpalGenAsyncParamCtrl.h>
|
||||
}
|
||||
|
||||
struct opal {
|
||||
int reply;
|
||||
int mode;
|
||||
int sequenceNo;
|
||||
int reply;
|
||||
int mode;
|
||||
int sequenceNo;
|
||||
|
||||
unsigned sendID;
|
||||
unsigned recvID;
|
||||
unsigned sendID;
|
||||
unsigned recvID;
|
||||
|
||||
Opal_SendAsyncParam sendParams;
|
||||
Opal_RecvAsyncParam recvParams;
|
||||
Opal_SendAsyncParam sendParams;
|
||||
Opal_RecvAsyncParam recvParams;
|
||||
};
|
||||
|
||||
int opal_type_start(SuperNode *sn);
|
||||
|
@ -41,15 +41,15 @@ int opal_type_stop();
|
|||
|
||||
int opal_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
char * opal_print(NodeCompat *n);
|
||||
char *opal_print(NodeCompat *n);
|
||||
|
||||
int opal_start(NodeCompat *n);
|
||||
|
||||
int opal_stop(NodeCompat *n);
|
||||
|
||||
int opal_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int opal_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int opal_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int opal_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -13,80 +13,71 @@
|
|||
|
||||
#include <sw/redis++/redis++.h>
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/task.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <villas/task.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
||||
enum class RedisMode {
|
||||
KEY,
|
||||
HASH,
|
||||
CHANNEL
|
||||
};
|
||||
enum class RedisMode { KEY, HASH, CHANNEL };
|
||||
|
||||
class RedisConnection {
|
||||
|
||||
public:
|
||||
sw::redis::Redis context;
|
||||
sw::redis::Redis context;
|
||||
|
||||
protected:
|
||||
enum State {
|
||||
INITIALIZED,
|
||||
RUNNING,
|
||||
STOPPING
|
||||
};
|
||||
enum State { INITIALIZED, RUNNING, STOPPING };
|
||||
|
||||
std::thread thread;
|
||||
std::atomic<enum State> state;
|
||||
std::thread thread;
|
||||
std::atomic<enum State> state;
|
||||
|
||||
void onMessage(const std::string &channel, const std::string &msg);
|
||||
void onMessage(const std::string &channel, const std::string &msg);
|
||||
|
||||
void loop();
|
||||
void loop();
|
||||
|
||||
std::unordered_multimap<std::string, NodeCompat *> subscriberMap;
|
||||
std::unordered_multimap<std::string, NodeCompat *> subscriberMap;
|
||||
|
||||
sw::redis::Subscriber subscriber;
|
||||
sw::redis::Subscriber subscriber;
|
||||
|
||||
villas::Logger logger;
|
||||
villas::Logger logger;
|
||||
|
||||
public:
|
||||
RedisConnection(const sw::redis::ConnectionOptions &opts);
|
||||
|
||||
RedisConnection(const sw::redis::ConnectionOptions &opts);
|
||||
static RedisConnection *get(const sw::redis::ConnectionOptions &opts);
|
||||
|
||||
static
|
||||
RedisConnection * get(const sw::redis::ConnectionOptions &opts);
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
void subscribe(NodeCompat *n, const std::string &channel);
|
||||
void unsubscribe(NodeCompat *n, const std::string &channel);
|
||||
void subscribe(NodeCompat *n, const std::string &channel);
|
||||
void unsubscribe(NodeCompat *n, const std::string &channel);
|
||||
};
|
||||
|
||||
struct redis {
|
||||
sw::redis::ConnectionOptions options;
|
||||
sw::redis::ConnectionOptions options;
|
||||
|
||||
RedisConnection *conn;
|
||||
RedisConnection *conn;
|
||||
|
||||
enum RedisMode mode;
|
||||
enum RedisMode mode;
|
||||
|
||||
std::string key;
|
||||
std::string key;
|
||||
|
||||
bool notify; // Use Redis Keyspace notifications to listen for updates.
|
||||
bool notify; // Use Redis Keyspace notifications to listen for updates.
|
||||
|
||||
struct Task task; // Timer for periodic events.
|
||||
double rate; // Rate for polling key updates if keyspace notifications are disabled.
|
||||
struct Task task; // Timer for periodic events.
|
||||
double
|
||||
rate; // Rate for polling key updates if keyspace notifications are disabled.
|
||||
|
||||
Format *formatter;
|
||||
Format *formatter;
|
||||
|
||||
struct Pool pool;
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
struct CQueueSignalled queue;
|
||||
};
|
||||
|
||||
int redis_init(NodeCompat *n);
|
||||
|
@ -95,7 +86,7 @@ int redis_destroy(NodeCompat *n);
|
|||
|
||||
int redis_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
char * redis_print(NodeCompat *n);
|
||||
char *redis_print(NodeCompat *n);
|
||||
|
||||
int redis_check(NodeCompat *n);
|
||||
|
||||
|
@ -109,9 +100,9 @@ int redis_pause(NodeCompat *n);
|
|||
|
||||
int redis_resume(NodeCompat *n);
|
||||
|
||||
int redis_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int redis_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int redis_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int redis_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int redis_reverse(NodeCompat *n);
|
||||
|
||||
|
|
|
@ -9,57 +9,42 @@
|
|||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <sw/redis++/redis++.h>
|
||||
#include <spdlog/fmt/ostr.h>
|
||||
#include <sw/redis++/redis++.h>
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
|
||||
namespace std {
|
||||
|
||||
template<typename _rep, typename ratio>
|
||||
struct hash<std::chrono::duration<_rep, ratio>>
|
||||
{
|
||||
std::size_t operator()(std::chrono::duration<_rep, ratio> const& s) const
|
||||
{
|
||||
return std::hash<_rep>{}(s.count());
|
||||
}
|
||||
template <typename _rep, typename ratio>
|
||||
struct hash<std::chrono::duration<_rep, ratio>> {
|
||||
std::size_t operator()(std::chrono::duration<_rep, ratio> const &s) const {
|
||||
return std::hash<_rep>{}(s.count());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<sw::redis::tls::TlsOptions>
|
||||
{
|
||||
std::size_t operator()(const sw::redis::tls::TlsOptions& t) const
|
||||
{
|
||||
template <> struct hash<sw::redis::tls::TlsOptions> {
|
||||
std::size_t operator()(const sw::redis::tls::TlsOptions &t) const {
|
||||
#ifdef REDISPP_WITH_TLS
|
||||
return hash<bool>()(t.enabled) ^
|
||||
hash<std::string>()(t.cacert) ^
|
||||
hash<std::string>()(t.cacertdir) ^
|
||||
hash<std::string>()(t.cert) ^
|
||||
hash<std::string>()(t.key) ^
|
||||
hash<std::string>()(t.sni);
|
||||
return hash<bool>()(t.enabled) ^ hash<std::string>()(t.cacert) ^
|
||||
hash<std::string>()(t.cacertdir) ^ hash<std::string>()(t.cert) ^
|
||||
hash<std::string>()(t.key) ^ hash<std::string>()(t.sni);
|
||||
#else
|
||||
return 0;
|
||||
return 0;
|
||||
#endif // REDISPP_WITH_TLS
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<sw::redis::ConnectionOptions>
|
||||
{
|
||||
std::size_t operator()(const sw::redis::ConnectionOptions& o) const
|
||||
{
|
||||
return hash<int>()(static_cast<int>(o.type)) ^
|
||||
hash<std::string>()(o.host) ^
|
||||
hash<int>()(o.port) ^
|
||||
hash<std::string>()(o.path) ^
|
||||
hash<std::string>()(o.user) ^
|
||||
hash<std::string>()(o.password) ^
|
||||
hash<int>()(o.db) ^
|
||||
hash<bool>()(o.keep_alive) ^
|
||||
hash<std::chrono::milliseconds>()(o.connect_timeout) ^
|
||||
hash<std::chrono::milliseconds>()(o.socket_timeout) ^
|
||||
hash<sw::redis::tls::TlsOptions>()(o.tls);
|
||||
}
|
||||
template <> struct hash<sw::redis::ConnectionOptions> {
|
||||
std::size_t operator()(const sw::redis::ConnectionOptions &o) const {
|
||||
return hash<int>()(static_cast<int>(o.type)) ^ hash<std::string>()(o.host) ^
|
||||
hash<int>()(o.port) ^ hash<std::string>()(o.path) ^
|
||||
hash<std::string>()(o.user) ^ hash<std::string>()(o.password) ^
|
||||
hash<int>()(o.db) ^ hash<bool>()(o.keep_alive) ^
|
||||
hash<std::chrono::milliseconds>()(o.connect_timeout) ^
|
||||
hash<std::chrono::milliseconds>()(o.socket_timeout) ^
|
||||
hash<sw::redis::tls::TlsOptions>()(o.tls);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
@ -67,140 +52,123 @@ struct hash<sw::redis::ConnectionOptions>
|
|||
namespace sw {
|
||||
namespace redis {
|
||||
|
||||
bool operator==(const tls::TlsOptions &o1, const tls::TlsOptions &o2)
|
||||
{
|
||||
bool operator==(const tls::TlsOptions &o1, const tls::TlsOptions &o2) {
|
||||
#ifdef REDISPP_WITH_TLS
|
||||
return o1.enabled == o2.enabled &&
|
||||
o1.cacert == o2.cacert &&
|
||||
o1.cacertdir == o2.cacertdir &&
|
||||
o1.cert == o2.cert &&
|
||||
o1.key == o2.key &&
|
||||
o1.sni == o2.sni;
|
||||
return o1.enabled == o2.enabled && o1.cacert == o2.cacert &&
|
||||
o1.cacertdir == o2.cacertdir && o1.cert == o2.cert &&
|
||||
o1.key == o2.key && o1.sni == o2.sni;
|
||||
#else
|
||||
return true;
|
||||
return true;
|
||||
#endif // REDISPP_WITH_TLS
|
||||
}
|
||||
|
||||
bool operator==(const ConnectionOptions &o1, const ConnectionOptions &o2)
|
||||
{
|
||||
return o1.type == o2.type &&
|
||||
o1.host == o2.host &&
|
||||
o1.port == o2.port &&
|
||||
o1.path == o2.path &&
|
||||
o1.user == o2.user &&
|
||||
o1.password == o2.password &&
|
||||
o1.db == o2.db &&
|
||||
o1.keep_alive == o2.keep_alive &&
|
||||
o1.connect_timeout == o2.connect_timeout &&
|
||||
o1.socket_timeout == o2.socket_timeout &&
|
||||
o1.tls == o2.tls;
|
||||
bool operator==(const ConnectionOptions &o1, const ConnectionOptions &o2) {
|
||||
return o1.type == o2.type && o1.host == o2.host && o1.port == o2.port &&
|
||||
o1.path == o2.path && o1.user == o2.user &&
|
||||
o1.password == o2.password && o1.db == o2.db &&
|
||||
o1.keep_alive == o2.keep_alive &&
|
||||
o1.connect_timeout == o2.connect_timeout &&
|
||||
o1.socket_timeout == o2.socket_timeout && o1.tls == o2.tls;
|
||||
}
|
||||
|
||||
#ifdef REDISPP_WITH_TLS
|
||||
template<typename OStream>
|
||||
OStream &operator<<(OStream &os, const tls::TlsOptions &t)
|
||||
{
|
||||
os << "tls.enabled=" << (t.enabled ? "yes" : "no");
|
||||
template <typename OStream>
|
||||
OStream &operator<<(OStream &os, const tls::TlsOptions &t) {
|
||||
os << "tls.enabled=" << (t.enabled ? "yes" : "no");
|
||||
|
||||
if (t.enabled) {
|
||||
if (!t.cacert.empty())
|
||||
os << ", tls.cacert=" << t.cacert;
|
||||
if (t.enabled) {
|
||||
if (!t.cacert.empty())
|
||||
os << ", tls.cacert=" << t.cacert;
|
||||
|
||||
if (!t.cacertdir.empty())
|
||||
os << ", tls.cacertdir=" << t.cacertdir;
|
||||
if (!t.cacertdir.empty())
|
||||
os << ", tls.cacertdir=" << t.cacertdir;
|
||||
|
||||
if (!t.cert.empty())
|
||||
os << ", tls.cert=" << t.cert;
|
||||
if (!t.cert.empty())
|
||||
os << ", tls.cert=" << t.cert;
|
||||
|
||||
if (!t.key.empty())
|
||||
os << ", tls.key=" << t.key;
|
||||
if (!t.key.empty())
|
||||
os << ", tls.key=" << t.key;
|
||||
|
||||
if (!t.sni.empty())
|
||||
os << ", tls.sni=" << t.sni;
|
||||
}
|
||||
if (!t.sni.empty())
|
||||
os << ", tls.sni=" << t.sni;
|
||||
}
|
||||
|
||||
return os;
|
||||
return os;
|
||||
}
|
||||
#endif // REDISPP_WITH_TLS
|
||||
|
||||
template<typename OStream>
|
||||
OStream &operator<<(OStream &os, const ConnectionType &t)
|
||||
{
|
||||
switch (t) {
|
||||
case ConnectionType::TCP:
|
||||
os << "tcp";
|
||||
break;
|
||||
template <typename OStream>
|
||||
OStream &operator<<(OStream &os, const ConnectionType &t) {
|
||||
switch (t) {
|
||||
case ConnectionType::TCP:
|
||||
os << "tcp";
|
||||
break;
|
||||
|
||||
case ConnectionType::UNIX:
|
||||
os << "unix";
|
||||
break;
|
||||
}
|
||||
case ConnectionType::UNIX:
|
||||
os << "unix";
|
||||
break;
|
||||
}
|
||||
|
||||
return os;
|
||||
return os;
|
||||
}
|
||||
|
||||
template<typename OStream>
|
||||
OStream &operator<<(OStream &os, const ConnectionOptions &o)
|
||||
{
|
||||
os << "type=" << o.type;
|
||||
template <typename OStream>
|
||||
OStream &operator<<(OStream &os, const ConnectionOptions &o) {
|
||||
os << "type=" << o.type;
|
||||
|
||||
switch (o.type) {
|
||||
case ConnectionType::TCP:
|
||||
os << ", host=" << o.host << ", port=" << o.port;
|
||||
break;
|
||||
switch (o.type) {
|
||||
case ConnectionType::TCP:
|
||||
os << ", host=" << o.host << ", port=" << o.port;
|
||||
break;
|
||||
|
||||
case ConnectionType::UNIX:
|
||||
os << ", path=" << o.path;
|
||||
break;
|
||||
}
|
||||
case ConnectionType::UNIX:
|
||||
os << ", path=" << o.path;
|
||||
break;
|
||||
}
|
||||
|
||||
os << ", db=" << o.db
|
||||
<< ", user=" << o.user
|
||||
<< ", keepalive=" << (o.keep_alive ? "yes" : "no");
|
||||
os << ", db=" << o.db << ", user=" << o.user
|
||||
<< ", keepalive=" << (o.keep_alive ? "yes" : "no");
|
||||
|
||||
#ifdef REDISPP_WITH_TLS
|
||||
os << ", " << o.tls;
|
||||
os << ", " << o.tls;
|
||||
#endif
|
||||
|
||||
return os;
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace redis
|
||||
} // namespace sw
|
||||
|
||||
template<typename OStream>
|
||||
OStream &operator<<(OStream &os, const enum villas::node::RedisMode &m)
|
||||
{
|
||||
switch (m) {
|
||||
case villas::node::RedisMode::KEY:
|
||||
os << "key";
|
||||
break;
|
||||
template <typename OStream>
|
||||
OStream &operator<<(OStream &os, const enum villas::node::RedisMode &m) {
|
||||
switch (m) {
|
||||
case villas::node::RedisMode::KEY:
|
||||
os << "key";
|
||||
break;
|
||||
|
||||
case villas::node::RedisMode::HASH:
|
||||
os << "hash";
|
||||
break;
|
||||
case villas::node::RedisMode::HASH:
|
||||
os << "hash";
|
||||
break;
|
||||
|
||||
case villas::node::RedisMode::CHANNEL:
|
||||
os << "channel";
|
||||
break;
|
||||
}
|
||||
case villas::node::RedisMode::CHANNEL:
|
||||
os << "channel";
|
||||
break;
|
||||
}
|
||||
|
||||
return os;
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
#ifdef REDISPP_WITH_URI
|
||||
sw::redis::ConnectionOptions make_redis_connection_options(char const *uri)
|
||||
{
|
||||
auto u = sw::redis::Uri { uri };
|
||||
return u.connection_options();
|
||||
}
|
||||
sw::redis::ConnectionOptions make_redis_connection_options(char const *uri) {
|
||||
auto u = sw::redis::Uri{uri};
|
||||
return u.connection_options();
|
||||
}
|
||||
#else
|
||||
sw::redis::ConnectionOptions make_redis_connection_options(char const *uri)
|
||||
{
|
||||
return sw::redis::ConnectionOptions { uri };
|
||||
}
|
||||
sw::redis::ConnectionOptions make_redis_connection_options(char const *uri) {
|
||||
return sw::redis::ConnectionOptions{uri};
|
||||
}
|
||||
#endif
|
||||
} // node
|
||||
} // villas
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -12,17 +12,17 @@
|
|||
|
||||
#include <fstream>
|
||||
|
||||
#include <villas/dsp/pid.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/hooks/decimate.hpp>
|
||||
#include <villas/hooks/limit_rate.hpp>
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <villas/hooks/limit_rate.hpp>
|
||||
#include <villas/hooks/decimate.hpp>
|
||||
#include <villas/dsp/pid.hpp>
|
||||
|
||||
extern "C" {
|
||||
#include <re/re_sa.h>
|
||||
#include <re/re_rtp.h>
|
||||
#include <re/re_sa.h>
|
||||
#include <re/re_rtp.h>
|
||||
}
|
||||
|
||||
namespace villas {
|
||||
|
@ -36,53 +36,49 @@ class SuperNode;
|
|||
#define RTP_INITIAL_BUFFER_LEN 1500
|
||||
#define RTP_PACKET_TYPE 21
|
||||
|
||||
enum class RTPHookType {
|
||||
DISABLED,
|
||||
DECIMATE,
|
||||
LIMIT_RATE
|
||||
};
|
||||
enum class RTPHookType { DISABLED, DECIMATE, LIMIT_RATE };
|
||||
|
||||
struct rtp {
|
||||
struct rtp_sock *rs; // RTP socket
|
||||
struct rtp_sock *rs; // RTP socket
|
||||
|
||||
struct {
|
||||
struct sa saddr_rtp; // Local/Remote address of the RTP socket
|
||||
struct sa saddr_rtcp; // Local/Remote address of the RTCP socket
|
||||
} in, out;
|
||||
struct {
|
||||
struct sa saddr_rtp; // Local/Remote address of the RTP socket
|
||||
struct sa saddr_rtcp; // Local/Remote address of the RTCP socket
|
||||
} in, out;
|
||||
|
||||
Format *formatter;
|
||||
Format *formatter;
|
||||
|
||||
struct {
|
||||
int enabled;
|
||||
struct {
|
||||
int enabled;
|
||||
|
||||
int num_rrs;
|
||||
} rtcp;
|
||||
int num_rrs;
|
||||
} rtcp;
|
||||
|
||||
struct {
|
||||
double a;
|
||||
double b;
|
||||
struct {
|
||||
double a;
|
||||
double b;
|
||||
|
||||
enum RTPHookType rate_hook_type;
|
||||
enum RTPHookType rate_hook_type;
|
||||
|
||||
LimitHook::Ptr rate_hook;
|
||||
dsp::PID rate_pid;
|
||||
LimitHook::Ptr rate_hook;
|
||||
dsp::PID rate_pid;
|
||||
|
||||
// PID parameters for rate controller
|
||||
double Kp, Ki, Kd;
|
||||
double rate_min;
|
||||
// PID parameters for rate controller
|
||||
double Kp, Ki, Kd;
|
||||
double rate_min;
|
||||
|
||||
double rate;
|
||||
double rate_source; // Sample rate of source
|
||||
double rate;
|
||||
double rate_source; // Sample rate of source
|
||||
|
||||
std::ofstream *log;
|
||||
char *log_filename;
|
||||
} aimd; // AIMD state
|
||||
std::ofstream *log;
|
||||
char *log_filename;
|
||||
} aimd; // AIMD state
|
||||
|
||||
struct CQueueSignalled recv_queue;
|
||||
struct mbuf *send_mb;
|
||||
struct CQueueSignalled recv_queue;
|
||||
struct mbuf *send_mb;
|
||||
};
|
||||
|
||||
char * rtp_print(NodeCompat *n);
|
||||
char *rtp_print(NodeCompat *n);
|
||||
|
||||
int rtp_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
|
@ -104,9 +100,9 @@ int rtp_netem_fds(NodeCompat *n, int fds[]);
|
|||
|
||||
int rtp_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
int rtp_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int rtp_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int rtp_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int rtp_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/node/memory.hpp>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/queue.h>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/shmem.hpp>
|
||||
|
||||
namespace villas {
|
||||
|
@ -20,14 +20,14 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
struct shmem {
|
||||
const char* out_name; // Name of the shm object for the output queue.
|
||||
const char* in_name; // Name of the shm object for the input queue.
|
||||
struct ShmemConfig conf; // Interface configuration struct.
|
||||
char **exec; // External program to execute on start.
|
||||
struct ShmemInterface intf; // Shmem interface
|
||||
const char *out_name; // Name of the shm object for the output queue.
|
||||
const char *in_name; // Name of the shm object for the input queue.
|
||||
struct ShmemConfig conf; // Interface configuration struct.
|
||||
char **exec; // External program to execute on start.
|
||||
struct ShmemInterface intf; // Shmem interface
|
||||
};
|
||||
|
||||
char * shmem_print(NodeCompat *n);
|
||||
char *shmem_print(NodeCompat *n);
|
||||
|
||||
int shmem_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
|
@ -39,9 +39,9 @@ int shmem_init(NodeCompat *n);
|
|||
|
||||
int shmem_prepare(NodeCompat *n);
|
||||
|
||||
int shmem_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int shmem_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int shmem_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int shmem_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/timing.hpp>
|
||||
#include <villas/task.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/task.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -20,86 +20,80 @@ struct Sample;
|
|||
class SignalNodeSignal {
|
||||
|
||||
public:
|
||||
enum class Type {
|
||||
RANDOM,
|
||||
SINE,
|
||||
SQUARE,
|
||||
TRIANGLE,
|
||||
RAMP,
|
||||
COUNTER,
|
||||
CONSTANT,
|
||||
PULSE,
|
||||
MIXED
|
||||
};
|
||||
enum class Type {
|
||||
RANDOM,
|
||||
SINE,
|
||||
SQUARE,
|
||||
TRIANGLE,
|
||||
RAMP,
|
||||
COUNTER,
|
||||
CONSTANT,
|
||||
PULSE,
|
||||
MIXED
|
||||
};
|
||||
|
||||
enum Type type;
|
||||
enum Type type;
|
||||
|
||||
double frequency; // Frequency of the generated signals.
|
||||
double amplitude; // Amplitude of the generated signals.
|
||||
double stddev; // Standard deviation of random signals (normal distributed).
|
||||
double offset; // A constant bias.
|
||||
double pulse_width; // Width of a pulse with respect to the rate (duration = pulse_width/rate)
|
||||
double pulse_low; // Amplitude when pulse signal is off
|
||||
double pulse_high; // Amplitude when pulse signal is on
|
||||
double phase; // Phase (rad) offset with respect to program start
|
||||
double last; // The values from the previous period which are required for random walk.
|
||||
double frequency; // Frequency of the generated signals.
|
||||
double amplitude; // Amplitude of the generated signals.
|
||||
double stddev; // Standard deviation of random signals (normal distributed).
|
||||
double offset; // A constant bias.
|
||||
double
|
||||
pulse_width; // Width of a pulse with respect to the rate (duration = pulse_width/rate)
|
||||
double pulse_low; // Amplitude when pulse signal is off
|
||||
double pulse_high; // Amplitude when pulse signal is on
|
||||
double phase; // Phase (rad) offset with respect to program start
|
||||
double
|
||||
last; // The values from the previous period which are required for random walk.
|
||||
|
||||
public:
|
||||
SignalNodeSignal(json_t *json);
|
||||
SignalNodeSignal(json_t *json);
|
||||
|
||||
int parse(json_t *json);
|
||||
int parse(json_t *json);
|
||||
|
||||
static
|
||||
enum Type lookupType(const std::string &type);
|
||||
static enum Type lookupType(const std::string &type);
|
||||
|
||||
static
|
||||
std::string typeToString(enum Type type);
|
||||
static std::string typeToString(enum Type type);
|
||||
|
||||
void start();
|
||||
void start();
|
||||
|
||||
void read(unsigned c, double t, double rate, SignalData *d);
|
||||
void read(unsigned c, double t, double rate, SignalData *d);
|
||||
|
||||
Signal::Ptr toSignal(Signal::Ptr tpl) const;
|
||||
Signal::Ptr toSignal(Signal::Ptr tpl) const;
|
||||
};
|
||||
|
||||
class SignalNode : public Node {
|
||||
|
||||
protected:
|
||||
std::vector<SignalNodeSignal> signals;
|
||||
std::vector<SignalNodeSignal> signals;
|
||||
|
||||
struct Task task; // Timer for periodic events.
|
||||
int rt; // Real-time mode?
|
||||
struct Task task; // Timer for periodic events.
|
||||
int rt; // Real-time mode?
|
||||
|
||||
double rate; // Sampling rate.
|
||||
bool monitor_missed; // Boolean, if set, node counts missed steps and warns user.
|
||||
int limit; // The number of values which should be generated by this node. <0 for infinite.
|
||||
double rate; // Sampling rate.
|
||||
bool
|
||||
monitor_missed; // Boolean, if set, node counts missed steps and warns user.
|
||||
int limit; // The number of values which should be generated by this node. <0 for infinite.
|
||||
|
||||
struct timespec started; // Point in time when this node was started.
|
||||
unsigned missed_steps; // Total number of missed steps.
|
||||
struct timespec started; // Point in time when this node was started.
|
||||
unsigned missed_steps; // Total number of missed steps.
|
||||
|
||||
virtual
|
||||
int _read(struct Sample *smps[], unsigned cnt);
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
SignalNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
SignalNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
virtual
|
||||
const std::string & getDetails();
|
||||
virtual const std::string &getDetails();
|
||||
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
virtual
|
||||
int start();
|
||||
virtual int start();
|
||||
|
||||
virtual
|
||||
int stop();
|
||||
virtual int stop();
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
virtual int prepare();
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs();
|
||||
virtual std::vector<int> getPollFDs();
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/timing.hpp>
|
||||
#include <villas/task.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -18,43 +18,46 @@ class NodeCompat;
|
|||
struct Sample;
|
||||
|
||||
struct signal_node {
|
||||
struct Task task; // Timer for periodic events.
|
||||
int rt; // Real-time mode?
|
||||
struct Task task; // Timer for periodic events.
|
||||
int rt; // Real-time mode?
|
||||
|
||||
enum class SignalType {
|
||||
RANDOM,
|
||||
SINE,
|
||||
SQUARE,
|
||||
TRIANGLE,
|
||||
RAMP,
|
||||
COUNTER,
|
||||
CONSTANT,
|
||||
MIXED,
|
||||
PULSE
|
||||
} *type; // Signal type
|
||||
enum class SignalType {
|
||||
RANDOM,
|
||||
SINE,
|
||||
SQUARE,
|
||||
TRIANGLE,
|
||||
RAMP,
|
||||
COUNTER,
|
||||
CONSTANT,
|
||||
MIXED,
|
||||
PULSE
|
||||
} *
|
||||
type; // Signal type
|
||||
|
||||
double rate; // Sampling rate.
|
||||
double *frequency; // Frequency of the generated signals.
|
||||
double *amplitude; // Amplitude of the generated signals.
|
||||
double *stddev; // Standard deviation of random signals (normal distributed).
|
||||
double *offset; // A constant bias.
|
||||
double *pulse_width; // Width of a pulse with respect to the rate (duration = pulse_width/rate)
|
||||
double *pulse_low; // Amplitude when pulse signal is off
|
||||
double *pulse_high; // Amplitude when pulse signal is on
|
||||
double *phase; // Phase (rad) offset with respect to program start
|
||||
int monitor_missed; // Boolean, if set, node counts missed steps and warns user.
|
||||
double rate; // Sampling rate.
|
||||
double *frequency; // Frequency of the generated signals.
|
||||
double *amplitude; // Amplitude of the generated signals.
|
||||
double *stddev; // Standard deviation of random signals (normal distributed).
|
||||
double *offset; // A constant bias.
|
||||
double *
|
||||
pulse_width; // Width of a pulse with respect to the rate (duration = pulse_width/rate)
|
||||
double *pulse_low; // Amplitude when pulse signal is off
|
||||
double *pulse_high; // Amplitude when pulse signal is on
|
||||
double *phase; // Phase (rad) offset with respect to program start
|
||||
int monitor_missed; // Boolean, if set, node counts missed steps and warns user.
|
||||
|
||||
double *last; // The values from the previous period which are required for random walk.
|
||||
double *
|
||||
last; // The values from the previous period which are required for random walk.
|
||||
|
||||
unsigned values; // The number of values which will be emitted by this node.
|
||||
int limit; // The number of values which should be generated by this node. <0 for infinitve.
|
||||
unsigned values; // The number of values which will be emitted by this node.
|
||||
int limit; // The number of values which should be generated by this node. <0 for infinitve.
|
||||
|
||||
struct timespec started; // Point in time when this node was started.
|
||||
unsigned counter; // The number of packets already emitted.
|
||||
unsigned missed_steps; // Total number of missed steps.
|
||||
struct timespec started; // Point in time when this node was started.
|
||||
unsigned counter; // The number of packets already emitted.
|
||||
unsigned missed_steps; // Total number of missed steps.
|
||||
};
|
||||
|
||||
char * signal_node_print(NodeCompat *n);
|
||||
char *signal_node_print(NodeCompat *n);
|
||||
|
||||
int signal_node_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
|
@ -68,7 +71,7 @@ int signal_node_destroy(NodeCompat *n);
|
|||
|
||||
int signal_node_prepare(NodeCompat *n);
|
||||
|
||||
int signal_node_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int signal_node_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int signal_node_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/socket_addr.hpp>
|
||||
#include <villas/format.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -18,29 +18,30 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
// The maximum length of a packet which contains stuct msg.
|
||||
#define SOCKET_INITIAL_BUFFER_LEN (64*1024)
|
||||
#define SOCKET_INITIAL_BUFFER_LEN (64 * 1024)
|
||||
|
||||
struct Socket {
|
||||
int sd; // The socket descriptor
|
||||
int verify_source; // Verify the source address of incoming packets against socket::remote.
|
||||
int sd; // The socket descriptor
|
||||
int verify_source; // Verify the source address of incoming packets against socket::remote.
|
||||
|
||||
enum SocketLayer layer; // The OSI / IP layer which should be used for this socket
|
||||
enum SocketLayer
|
||||
layer; // The OSI / IP layer which should be used for this socket
|
||||
|
||||
Format *formatter;
|
||||
Format *formatter;
|
||||
|
||||
// Multicast options
|
||||
struct multicast {
|
||||
int enabled; // Is multicast enabled?
|
||||
unsigned char loop; // Loopback multicast packets to local host?
|
||||
unsigned char ttl; // The time to live for multicast packets.
|
||||
struct ip_mreq mreq; // A multicast group to join.
|
||||
} multicast;
|
||||
// Multicast options
|
||||
struct multicast {
|
||||
int enabled; // Is multicast enabled?
|
||||
unsigned char loop; // Loopback multicast packets to local host?
|
||||
unsigned char ttl; // The time to live for multicast packets.
|
||||
struct ip_mreq mreq; // A multicast group to join.
|
||||
} multicast;
|
||||
|
||||
struct {
|
||||
char *buf; // Buffer for receiving messages
|
||||
size_t buflen;
|
||||
union sockaddr_union saddr; // Remote address of the socket
|
||||
} in, out;
|
||||
struct {
|
||||
char *buf; // Buffer for receiving messages
|
||||
size_t buflen;
|
||||
union sockaddr_union saddr; // Remote address of the socket
|
||||
} in, out;
|
||||
};
|
||||
|
||||
int socket_type_start(SuperNode *sn);
|
||||
|
@ -61,13 +62,13 @@ int socket_reverse(NodeCompat *n);
|
|||
|
||||
int socket_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
int socket_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int socket_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int socket_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int socket_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int socket_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
char * socket_print(NodeCompat *n);
|
||||
char *socket_print(NodeCompat *n);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
|
||||
#include <jansson.h>
|
||||
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/stats.hpp>
|
||||
#include <villas/task.hpp>
|
||||
#include <villas/list.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -20,19 +20,19 @@ namespace node {
|
|||
class NodeCompat;
|
||||
|
||||
struct stats_node_signal {
|
||||
Node *node;
|
||||
char *node_str;
|
||||
Node *node;
|
||||
char *node_str;
|
||||
|
||||
enum villas::Stats::Metric metric;
|
||||
enum villas::Stats::Type type;
|
||||
enum villas::Stats::Metric metric;
|
||||
enum villas::Stats::Type type;
|
||||
};
|
||||
|
||||
struct stats_node {
|
||||
double rate;
|
||||
double rate;
|
||||
|
||||
struct Task task;
|
||||
struct Task task;
|
||||
|
||||
struct List signals; // List of type struct stats_node_signal
|
||||
struct List signals; // List of type struct stats_node_signal
|
||||
};
|
||||
|
||||
int stats_node_type_start(SuperNode *sn);
|
||||
|
@ -51,7 +51,7 @@ int stats_node_start(NodeCompat *n);
|
|||
|
||||
int stats_node_stop(NodeCompat *n);
|
||||
|
||||
int stats_node_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int stats_node_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int stats_node_parse_signal(struct stats_node_signal *s, json_t *json);
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
#include <villas/usb.hpp>
|
||||
#include <villas/log.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -22,123 +22,86 @@ class NodeCompat;
|
|||
class TEMPerDevice : public villas::usb::Device {
|
||||
|
||||
protected:
|
||||
constexpr static
|
||||
unsigned char question_temperature[] = { 0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00 };
|
||||
constexpr static unsigned char question_temperature[] = {
|
||||
0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
float scale;
|
||||
float offset;
|
||||
float scale;
|
||||
float offset;
|
||||
|
||||
int timeout;
|
||||
int timeout;
|
||||
|
||||
villas::Logger logger;
|
||||
villas::Logger logger;
|
||||
|
||||
virtual void decode(unsigned char *answer, float *temp) = 0;
|
||||
|
||||
virtual
|
||||
void decode(unsigned char *answer, float *temp) = 0;
|
||||
public:
|
||||
static
|
||||
TEMPerDevice * make(struct libusb_device *desc);
|
||||
static TEMPerDevice *make(struct libusb_device *desc);
|
||||
|
||||
TEMPerDevice(struct libusb_device *dev);
|
||||
virtual
|
||||
~TEMPerDevice()
|
||||
{ }
|
||||
TEMPerDevice(struct libusb_device *dev);
|
||||
virtual ~TEMPerDevice() {}
|
||||
|
||||
void open(bool reset = true);
|
||||
void close();
|
||||
void open(bool reset = true);
|
||||
void close();
|
||||
|
||||
virtual
|
||||
int getNumSensors() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
virtual int getNumSensors() const { return 1; }
|
||||
|
||||
virtual
|
||||
bool hasHumiditySensor() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool hasHumiditySensor() const { return false; }
|
||||
|
||||
void read(struct Sample *smp);
|
||||
void read(struct Sample *smp);
|
||||
};
|
||||
|
||||
class TEMPer1Device : public TEMPerDevice {
|
||||
|
||||
protected:
|
||||
virtual
|
||||
void decode(unsigned char *answer, float *temp);
|
||||
virtual void decode(unsigned char *answer, float *temp);
|
||||
|
||||
using TEMPerDevice::TEMPerDevice;
|
||||
using TEMPerDevice::TEMPerDevice;
|
||||
|
||||
public:
|
||||
static
|
||||
bool match(struct libusb_device *dev);
|
||||
static bool match(struct libusb_device *dev);
|
||||
|
||||
static
|
||||
std::string getName()
|
||||
{
|
||||
return "TEMPer1";
|
||||
}
|
||||
static std::string getName() { return "TEMPer1"; }
|
||||
};
|
||||
|
||||
class TEMPer2Device : public TEMPer1Device {
|
||||
|
||||
protected:
|
||||
virtual
|
||||
void decode(unsigned char *answer, float *temp);
|
||||
virtual void decode(unsigned char *answer, float *temp);
|
||||
|
||||
using TEMPer1Device::TEMPer1Device;
|
||||
using TEMPer1Device::TEMPer1Device;
|
||||
|
||||
public:
|
||||
static
|
||||
bool match(struct libusb_device *dev);
|
||||
static bool match(struct libusb_device *dev);
|
||||
|
||||
static
|
||||
std::string getName()
|
||||
{
|
||||
return "TEMPer2";
|
||||
}
|
||||
static std::string getName() { return "TEMPer2"; }
|
||||
|
||||
virtual
|
||||
int getNumSensors() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
virtual int getNumSensors() const { return 2; }
|
||||
};
|
||||
|
||||
class TEMPerHUMDevice : public TEMPerDevice {
|
||||
|
||||
protected:
|
||||
virtual
|
||||
void decode(unsigned char *answer, float *temp);
|
||||
virtual void decode(unsigned char *answer, float *temp);
|
||||
|
||||
using TEMPerDevice::TEMPerDevice;
|
||||
using TEMPerDevice::TEMPerDevice;
|
||||
|
||||
public:
|
||||
static
|
||||
bool match(struct libusb_device *dev);
|
||||
static bool match(struct libusb_device *dev);
|
||||
|
||||
static
|
||||
std::string getName()
|
||||
{
|
||||
return "TEMPerHUM";
|
||||
}
|
||||
static std::string getName() { return "TEMPerHUM"; }
|
||||
|
||||
virtual
|
||||
bool hasHumiditySensor() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual bool hasHumiditySensor() const { return true; }
|
||||
};
|
||||
|
||||
struct temper {
|
||||
struct {
|
||||
double scale;
|
||||
double offset;
|
||||
} calibration;
|
||||
struct {
|
||||
double scale;
|
||||
double offset;
|
||||
} calibration;
|
||||
|
||||
struct villas::usb::Filter filter;
|
||||
struct villas::usb::Filter filter;
|
||||
|
||||
TEMPerDevice *device;
|
||||
TEMPerDevice *device;
|
||||
};
|
||||
|
||||
int temper_type_start(SuperNode *sn);
|
||||
|
@ -153,7 +116,7 @@ int temper_destroy(NodeCompat *n);
|
|||
|
||||
int temper_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
char * temper_print(NodeCompat *n);
|
||||
char *temper_print(NodeCompat *n);
|
||||
|
||||
int temper_check();
|
||||
|
||||
|
@ -167,9 +130,9 @@ int temper_pause(NodeCompat *n);
|
|||
|
||||
int temper_resume(NodeCompat *n);
|
||||
|
||||
int temper_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int temper_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int temper_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int temper_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int temper_reverse(NodeCompat *n);
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/task.hpp>
|
||||
|
||||
namespace villas {
|
||||
|
@ -21,33 +21,33 @@ struct Sample;
|
|||
struct test_rtt;
|
||||
|
||||
struct test_rtt_case {
|
||||
double rate;
|
||||
unsigned values;
|
||||
unsigned limit; // The number of samples we take per test.
|
||||
double rate;
|
||||
unsigned values;
|
||||
unsigned limit; // The number of samples we take per test.
|
||||
|
||||
char *filename;
|
||||
char *filename_formatted;
|
||||
char *filename;
|
||||
char *filename_formatted;
|
||||
|
||||
NodeCompat *node;
|
||||
NodeCompat *node;
|
||||
};
|
||||
|
||||
struct test_rtt {
|
||||
struct Task task; // The periodic task for test_rtt_read()
|
||||
Format *formatter;// The format of the output file
|
||||
FILE *stream;
|
||||
struct Task task; // The periodic task for test_rtt_read()
|
||||
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 counter;
|
||||
int current; // Index of current test in test_rtt::cases
|
||||
int counter;
|
||||
|
||||
struct List cases; // List of test cases
|
||||
struct List 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.
|
||||
};
|
||||
|
||||
char * test_rtt_print(NodeCompat *n);
|
||||
char *test_rtt_print(NodeCompat *n);
|
||||
|
||||
int test_rtt_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
|
@ -61,9 +61,9 @@ int test_rtt_start(NodeCompat *n);
|
|||
|
||||
int test_rtt_stop(NodeCompat *n);
|
||||
|
||||
int test_rtt_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int test_rtt_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int test_rtt_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int test_rtt_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int test_rtt_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <villas/pool.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
|
||||
#include <uldaq.h>
|
||||
|
||||
|
@ -22,34 +22,34 @@ namespace villas {
|
|||
namespace node {
|
||||
|
||||
struct uldaq {
|
||||
const char *device_id;
|
||||
const char *device_id;
|
||||
|
||||
DaqDeviceHandle device_handle;
|
||||
DaqDeviceDescriptor *device_descriptor;
|
||||
DaqDeviceInterface device_interface_type;
|
||||
DaqDeviceHandle device_handle;
|
||||
DaqDeviceDescriptor *device_descriptor;
|
||||
DaqDeviceInterface device_interface_type;
|
||||
|
||||
uint64_t sequence;
|
||||
uint64_t sequence;
|
||||
|
||||
struct {
|
||||
double sample_rate;
|
||||
double *buffer;
|
||||
size_t buffer_len;
|
||||
size_t buffer_pos;
|
||||
size_t channel_count;
|
||||
struct {
|
||||
double sample_rate;
|
||||
double *buffer;
|
||||
size_t buffer_len;
|
||||
size_t buffer_pos;
|
||||
size_t channel_count;
|
||||
|
||||
ScanOption scan_options;
|
||||
AInScanFlag flags;
|
||||
AiQueueElement *queues;
|
||||
ScanStatus status; // protected by mutex
|
||||
TransferStatus transfer_status; // protected by mutex
|
||||
ScanOption scan_options;
|
||||
AInScanFlag flags;
|
||||
AiQueueElement *queues;
|
||||
ScanStatus status; // protected by mutex
|
||||
TransferStatus transfer_status; // protected by mutex
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cv;
|
||||
} in;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cv;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
// TODO
|
||||
} out;
|
||||
struct {
|
||||
// TODO
|
||||
} out;
|
||||
};
|
||||
|
||||
int uldaq_type_start(SuperNode *sn);
|
||||
|
@ -60,7 +60,7 @@ int uldaq_destroy(NodeCompat *n);
|
|||
|
||||
int uldaq_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
char * uldaq_print(NodeCompat *n);
|
||||
char *uldaq_print(NodeCompat *n);
|
||||
|
||||
int uldaq_check(NodeCompat *n);
|
||||
|
||||
|
@ -68,7 +68,7 @@ int uldaq_start(NodeCompat *n);
|
|||
|
||||
int uldaq_stop(NodeCompat *n);
|
||||
|
||||
int uldaq_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
|
||||
int uldaq_read(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
|
||||
#include <rtc/rtc.hpp>
|
||||
|
||||
#include <villas/nodes/webrtc/peer_connection.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/timing.hpp>
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/nodes/webrtc/peer_connection.hpp>
|
||||
#include <villas/queue_signalled.h>
|
||||
#include <villas/timing.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -27,91 +27,70 @@ struct Sample;
|
|||
class WebRTCNode : public Node {
|
||||
|
||||
protected:
|
||||
std::string server;
|
||||
std::string session;
|
||||
std::string peer;
|
||||
std::string server;
|
||||
std::string session;
|
||||
std::string peer;
|
||||
|
||||
int wait_seconds;
|
||||
Format *format;
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
int wait_seconds;
|
||||
Format *format;
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
|
||||
std::shared_ptr<webrtc::PeerConnection> conn;
|
||||
rtc::Configuration rtcConf;
|
||||
rtc::DataChannelInit dci;
|
||||
std::shared_ptr<webrtc::PeerConnection> conn;
|
||||
rtc::Configuration rtcConf;
|
||||
rtc::DataChannelInit dci;
|
||||
|
||||
virtual
|
||||
int _read(struct Sample *smps[], unsigned cnt);
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int _write(struct Sample *smps[], unsigned cnt);
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
json_t * _readStatus() const;
|
||||
virtual json_t *_readStatus() const;
|
||||
|
||||
public:
|
||||
WebRTCNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
WebRTCNode(const uuid_t &id = {}, const std::string &name = "");
|
||||
|
||||
virtual
|
||||
~WebRTCNode();
|
||||
virtual ~WebRTCNode();
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
virtual int prepare();
|
||||
|
||||
virtual
|
||||
int parse(json_t *json);
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
virtual
|
||||
int start();
|
||||
virtual int start();
|
||||
|
||||
virtual
|
||||
int stop();
|
||||
virtual int stop();
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs();
|
||||
virtual std::vector<int> getPollFDs();
|
||||
|
||||
virtual
|
||||
const std::string & getDetails();
|
||||
virtual const std::string &getDetails();
|
||||
};
|
||||
|
||||
class WebRTCNodeFactory : public NodeFactory {
|
||||
|
||||
public:
|
||||
using NodeFactory::NodeFactory;
|
||||
using NodeFactory::NodeFactory;
|
||||
|
||||
virtual
|
||||
Node * make(const uuid_t &id = {}, const std::string &nme = "")
|
||||
{
|
||||
auto *n = new WebRTCNode(id, nme);
|
||||
virtual Node *make(const uuid_t &id = {}, const std::string &nme = "") {
|
||||
auto *n = new WebRTCNode(id, nme);
|
||||
|
||||
init(n);
|
||||
init(n);
|
||||
|
||||
return n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
virtual
|
||||
int getFlags() const
|
||||
{
|
||||
return (int) NodeFactory::Flags::SUPPORTS_READ |
|
||||
(int) NodeFactory::Flags::SUPPORTS_WRITE |
|
||||
(int) NodeFactory::Flags::SUPPORTS_POLL |
|
||||
(int) NodeFactory::Flags::REQUIRES_WEB;
|
||||
}
|
||||
virtual int getFlags() const {
|
||||
return (int)NodeFactory::Flags::SUPPORTS_READ |
|
||||
(int)NodeFactory::Flags::SUPPORTS_WRITE |
|
||||
(int)NodeFactory::Flags::SUPPORTS_POLL |
|
||||
(int)NodeFactory::Flags::REQUIRES_WEB;
|
||||
}
|
||||
|
||||
virtual
|
||||
std::string getName() const
|
||||
{
|
||||
return "webrtc";
|
||||
}
|
||||
virtual std::string getName() const { return "webrtc"; }
|
||||
|
||||
virtual
|
||||
std::string getDescription() const
|
||||
{
|
||||
return "Web Real-time Communication";
|
||||
}
|
||||
virtual std::string getDescription() const {
|
||||
return "Web Real-time Communication";
|
||||
}
|
||||
|
||||
virtual
|
||||
int start(SuperNode *sn);
|
||||
virtual int start(SuperNode *sn);
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
#include <rtc/rtc.hpp>
|
||||
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/web.hpp>
|
||||
#include <villas/signal_list.hpp>
|
||||
#include <villas/nodes/webrtc/signaling_client.hpp>
|
||||
#include <villas/signal_list.hpp>
|
||||
#include <villas/web.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -24,69 +24,72 @@ namespace webrtc {
|
|||
class PeerConnection {
|
||||
|
||||
public:
|
||||
PeerConnection(const std::string &server, const std::string &session, const std::string &peer, std::shared_ptr<SignalList> signals, rtc::Configuration config, Web *w, rtc::DataChannelInit d);
|
||||
~PeerConnection();
|
||||
PeerConnection(const std::string &server, const std::string &session,
|
||||
const std::string &peer, std::shared_ptr<SignalList> signals,
|
||||
rtc::Configuration config, Web *w, rtc::DataChannelInit d);
|
||||
~PeerConnection();
|
||||
|
||||
bool waitForDataChannel(std::chrono::seconds timeout);
|
||||
void onMessage(std::function<void(rtc::binary)> callback);
|
||||
void sendMessage(rtc::binary msg);
|
||||
bool waitForDataChannel(std::chrono::seconds timeout);
|
||||
void onMessage(std::function<void(rtc::binary)> callback);
|
||||
void sendMessage(rtc::binary msg);
|
||||
|
||||
json_t * readStatus() const;
|
||||
json_t *readStatus() const;
|
||||
|
||||
void connect();
|
||||
void disconnect();
|
||||
void connect();
|
||||
void disconnect();
|
||||
|
||||
protected:
|
||||
Web *web;
|
||||
std::vector<rtc::IceServer> extraServers;
|
||||
rtc::DataChannelInit dataChannelInit;
|
||||
rtc::Configuration defaultConfig;
|
||||
Web *web;
|
||||
std::vector<rtc::IceServer> extraServers;
|
||||
rtc::DataChannelInit dataChannelInit;
|
||||
rtc::Configuration defaultConfig;
|
||||
|
||||
std::shared_ptr<rtc::PeerConnection> conn;
|
||||
std::shared_ptr<rtc::DataChannel> chan;
|
||||
std::shared_ptr<SignalingClient> client;
|
||||
std::shared_ptr<SignalList> signals;
|
||||
std::shared_ptr<rtc::PeerConnection> conn;
|
||||
std::shared_ptr<rtc::DataChannel> chan;
|
||||
std::shared_ptr<SignalingClient> client;
|
||||
std::shared_ptr<SignalList> signals;
|
||||
|
||||
Logger logger;
|
||||
Logger logger;
|
||||
|
||||
std::mutex mutex;
|
||||
std::mutex mutex;
|
||||
|
||||
std::condition_variable_any startupCondition;
|
||||
bool stopStartup;
|
||||
std::condition_variable_any startupCondition;
|
||||
bool stopStartup;
|
||||
|
||||
bool warnNotConnected;
|
||||
bool standby;
|
||||
bool first;
|
||||
int firstID;
|
||||
int secondID;
|
||||
bool warnNotConnected;
|
||||
bool standby;
|
||||
bool first;
|
||||
int firstID;
|
||||
int secondID;
|
||||
|
||||
std::function<void(rtc::binary)> onMessageCallback;
|
||||
std::function<void(rtc::binary)> onMessageCallback;
|
||||
|
||||
void resetConnection(std::unique_lock<decltype(PeerConnection::mutex)> &lock);
|
||||
void resetConnectionAndStandby(std::unique_lock<decltype(PeerConnection::mutex)> &lock);
|
||||
void notifyStartup();
|
||||
void resetConnection(std::unique_lock<decltype(PeerConnection::mutex)> &lock);
|
||||
void resetConnectionAndStandby(
|
||||
std::unique_lock<decltype(PeerConnection::mutex)> &lock);
|
||||
void notifyStartup();
|
||||
|
||||
void setupPeerConnection(std::shared_ptr<rtc::PeerConnection> = nullptr);
|
||||
void setupDataChannel(std::shared_ptr<rtc::DataChannel> = nullptr);
|
||||
void setupPeerConnection(std::shared_ptr<rtc::PeerConnection> = nullptr);
|
||||
void setupDataChannel(std::shared_ptr<rtc::DataChannel> = nullptr);
|
||||
|
||||
void onLocalDescription(rtc::Description sdp);
|
||||
void onLocalCandidate(rtc::Candidate cand);
|
||||
void onLocalDescription(rtc::Description sdp);
|
||||
void onLocalCandidate(rtc::Candidate cand);
|
||||
|
||||
void onConnectionStateChange(rtc::PeerConnection::State state);
|
||||
void onSignalingStateChange(rtc::PeerConnection::SignalingState state);
|
||||
void onGatheringStateChange(rtc::PeerConnection::GatheringState state);
|
||||
void onConnectionStateChange(rtc::PeerConnection::State state);
|
||||
void onSignalingStateChange(rtc::PeerConnection::SignalingState state);
|
||||
void onGatheringStateChange(rtc::PeerConnection::GatheringState state);
|
||||
|
||||
void onSignalingConnected();
|
||||
void onSignalingDisconnected();
|
||||
void onSignalingError(std::string err);
|
||||
void onSignalingMessage(SignalingMessage msg);
|
||||
void onSignalingConnected();
|
||||
void onSignalingDisconnected();
|
||||
void onSignalingError(std::string err);
|
||||
void onSignalingMessage(SignalingMessage msg);
|
||||
|
||||
void onDataChannel(std::shared_ptr<rtc::DataChannel> dc);
|
||||
void onDataChannelOpen();
|
||||
void onDataChannelClosed();
|
||||
void onDataChannelError(std::string err);
|
||||
void onDataChannelMessage(rtc::string msg);
|
||||
void onDataChannelMessage(rtc::binary msg);
|
||||
void onDataChannel(std::shared_ptr<rtc::DataChannel> dc);
|
||||
void onDataChannelOpen();
|
||||
void onDataChannelClosed();
|
||||
void onDataChannelError(std::string err);
|
||||
void onDataChannelMessage(rtc::string msg);
|
||||
void onDataChannelMessage(rtc::binary msg);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -9,16 +9,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#include <villas/queue.hpp>
|
||||
#include <villas/buffer.hpp>
|
||||
#include <villas/web.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/nodes/webrtc/signaling_message.hpp>
|
||||
#include <villas/queue.hpp>
|
||||
#include <villas/web.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
@ -31,87 +31,82 @@ namespace webrtc {
|
|||
class SignalingClient {
|
||||
|
||||
protected:
|
||||
struct sul_offsetof_helper {
|
||||
lws_sorted_usec_list_t sul; // Schedule connection retry
|
||||
SignalingClient *self;
|
||||
} sul_helper;
|
||||
struct sul_offsetof_helper {
|
||||
lws_sorted_usec_list_t sul; // Schedule connection retry
|
||||
SignalingClient *self;
|
||||
} sul_helper;
|
||||
|
||||
uint16_t retry_count; // Count of consecutive retries
|
||||
uint16_t retry_count; // Count of consecutive retries
|
||||
|
||||
struct lws *wsi;
|
||||
struct lws_client_connect_info info;
|
||||
struct lws *wsi;
|
||||
struct lws_client_connect_info info;
|
||||
|
||||
// The retry and backoff policy we want to use for our client connections
|
||||
static constexpr
|
||||
uint32_t backoff_ms[] = { 1<<4, 1<<6, 1<<8, 1<<10, 1<<12, 1<<14, 1<<16 };
|
||||
static constexpr
|
||||
lws_retry_bo_t retry = {
|
||||
.retry_ms_table = backoff_ms,
|
||||
.retry_ms_table_count = LWS_ARRAY_SIZE(backoff_ms),
|
||||
.conceal_count = LWS_ARRAY_SIZE(backoff_ms) + 1,
|
||||
// The retry and backoff policy we want to use for our client connections
|
||||
static constexpr uint32_t backoff_ms[] = {1 << 4, 1 << 6, 1 << 8, 1 << 10,
|
||||
1 << 12, 1 << 14, 1 << 16};
|
||||
static constexpr lws_retry_bo_t retry = {
|
||||
.retry_ms_table = backoff_ms,
|
||||
.retry_ms_table_count = LWS_ARRAY_SIZE(backoff_ms),
|
||||
.conceal_count = LWS_ARRAY_SIZE(backoff_ms) + 1,
|
||||
|
||||
.secs_since_valid_ping = 3, // force PINGs after secs idle
|
||||
.secs_since_valid_hangup = 10, // hangup after secs idle
|
||||
.secs_since_valid_ping = 3, // force PINGs after secs idle
|
||||
.secs_since_valid_hangup = 10, // hangup after secs idle
|
||||
|
||||
.jitter_percent = 20,
|
||||
};
|
||||
.jitter_percent = 20,
|
||||
};
|
||||
|
||||
std::function<void(SignalingMessage)> cbMessage;
|
||||
std::function<void()> cbConnected;
|
||||
std::function<void()> cbDisconnected;
|
||||
std::function<void(std::string)> cbError;
|
||||
std::function<void(SignalingMessage)> cbMessage;
|
||||
std::function<void()> cbConnected;
|
||||
std::function<void()> cbDisconnected;
|
||||
std::function<void(std::string)> cbError;
|
||||
|
||||
Queue<SignalingMessage> outgoingMessages;
|
||||
Queue<SignalingMessage> outgoingMessages;
|
||||
|
||||
Web *web;
|
||||
Web *web;
|
||||
|
||||
char *uri;
|
||||
char *path;
|
||||
char *uri;
|
||||
char *path;
|
||||
|
||||
std::atomic<bool> running;
|
||||
std::atomic<bool> running;
|
||||
|
||||
Buffer buffer; // A buffer for received fragments before JSON decoding.
|
||||
Buffer buffer; // A buffer for received fragments before JSON decoding.
|
||||
|
||||
Logger logger;
|
||||
Logger logger;
|
||||
|
||||
int protocolCallback(struct lws *wsi, enum lws_callback_reasons reason, void *in, size_t len);
|
||||
int protocolCallback(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *in, size_t len);
|
||||
|
||||
static
|
||||
void connectStatic(struct lws_sorted_usec_list *sul);
|
||||
static void connectStatic(struct lws_sorted_usec_list *sul);
|
||||
|
||||
int writable();
|
||||
int writable();
|
||||
|
||||
public:
|
||||
SignalingClient(const std::string &server, const std::string &session, const std::string &peer, Web *w);
|
||||
~SignalingClient();
|
||||
SignalingClient(const std::string &server, const std::string &session,
|
||||
const std::string &peer, Web *w);
|
||||
~SignalingClient();
|
||||
|
||||
static
|
||||
int protocolCallbackStatic(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
||||
static int protocolCallbackStatic(struct lws *wsi,
|
||||
enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
|
||||
void connect();
|
||||
void disconnect();
|
||||
void connect();
|
||||
void disconnect();
|
||||
|
||||
void sendMessage(SignalingMessage);
|
||||
void sendMessage(SignalingMessage);
|
||||
|
||||
void onMessage(std::function<void(SignalingMessage)> callback)
|
||||
{
|
||||
cbMessage = callback;
|
||||
}
|
||||
void onMessage(std::function<void(SignalingMessage)> callback) {
|
||||
cbMessage = callback;
|
||||
}
|
||||
|
||||
void onConnected(std::function<void()> callback)
|
||||
{
|
||||
cbConnected = callback;
|
||||
}
|
||||
void onConnected(std::function<void()> callback) { cbConnected = callback; }
|
||||
|
||||
void onDisconnected(std::function<void()> callback)
|
||||
{
|
||||
cbDisconnected = callback;
|
||||
}
|
||||
void onDisconnected(std::function<void()> callback) {
|
||||
cbDisconnected = callback;
|
||||
}
|
||||
|
||||
void onError(std::function<void(std::string)> callback)
|
||||
{
|
||||
cbError = callback;
|
||||
}
|
||||
void onError(std::function<void(std::string)> callback) {
|
||||
cbError = callback;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <rtc/rtc.hpp>
|
||||
#include <jansson.h>
|
||||
#include <rtc/rtc.hpp>
|
||||
|
||||
#include <villas/signal_list.hpp>
|
||||
|
||||
|
@ -24,37 +24,38 @@ namespace node {
|
|||
namespace webrtc {
|
||||
|
||||
struct Peer {
|
||||
int id;
|
||||
std::string name;
|
||||
std::string remote;
|
||||
std::string userAgent;
|
||||
std::chrono::time_point<std::chrono::system_clock> created;
|
||||
int id;
|
||||
std::string name;
|
||||
std::string remote;
|
||||
std::string userAgent;
|
||||
std::chrono::time_point<std::chrono::system_clock> created;
|
||||
|
||||
Peer(json_t *j);
|
||||
json_t * toJson() const;
|
||||
Peer(json_t *j);
|
||||
json_t *toJson() const;
|
||||
};
|
||||
|
||||
struct RelayMessage {
|
||||
std::vector<rtc::IceServer> servers;
|
||||
std::vector<rtc::IceServer> servers;
|
||||
|
||||
RelayMessage(json_t *j);
|
||||
RelayMessage(json_t *j);
|
||||
};
|
||||
|
||||
struct ControlMessage {
|
||||
int peerID;
|
||||
std::vector<Peer> peers;
|
||||
int peerID;
|
||||
std::vector<Peer> peers;
|
||||
|
||||
ControlMessage(json_t *j);
|
||||
json_t * toJson() const;
|
||||
ControlMessage(json_t *j);
|
||||
json_t *toJson() const;
|
||||
};
|
||||
|
||||
struct SignalingMessage {
|
||||
std::variant<std::monostate, RelayMessage, ControlMessage, SignalList, rtc::Description, rtc::Candidate> message;
|
||||
std::variant<std::monostate, RelayMessage, ControlMessage, SignalList,
|
||||
rtc::Description, rtc::Candidate>
|
||||
message;
|
||||
|
||||
static
|
||||
SignalingMessage fromJson(json_t *j);
|
||||
json_t * toJson() const;
|
||||
std::string toString() const;
|
||||
static SignalingMessage fromJson(json_t *j);
|
||||
json_t *toJson() const;
|
||||
std::string toString() const;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue