Apply clang-format changes

Signed-off-by: Steffen Vogel <steffen.vogel@opal-rt.com>
This commit is contained in:
Steffen Vogel 2023-09-07 11:46:39 +02:00 committed by Steffen Vogel
parent 8da1e68b0f
commit 02a2aa4f94
300 changed files with 30949 additions and 33000 deletions

View File

@ -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_

View File

@ -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));

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -12,7 +12,7 @@
namespace villas {
namespace node {
json_t * getCapabilities();
json_t *getCapabilities();
} // namespace node
} // namepace vilals
} // namespace villas

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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.
*

View File

@ -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);

View File

@ -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>;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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[]);

View File

@ -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

View File

@ -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

View File

@ -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}};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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[]);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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[]);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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[]);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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[]);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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