mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
Merge branch 'master' into node-smu
This commit is contained in:
commit
652cf079ff
168 changed files with 12094 additions and 4527 deletions
|
@ -1,8 +1,5 @@
|
|||
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
"name": "VILLASnode",
|
||||
"image": "registry.git.rwth-aachen.de/acs/public/villas/node/dev-vscode",
|
||||
|
|
|
@ -48,7 +48,7 @@ prepare:docker:
|
|||
TARGET: dev-vscode
|
||||
DOCKER_IMAGE_DEV: ${DOCKER_IMAGE}/dev-vscode
|
||||
tags:
|
||||
- docker
|
||||
- docker-image-builder
|
||||
|
||||
# Stage: build
|
||||
|
||||
|
@ -92,10 +92,10 @@ test:python:
|
|||
stage: test
|
||||
script:
|
||||
- cd python
|
||||
- /venv/bin/black --check .
|
||||
- /venv/bin/pytest --verbose .
|
||||
- /venv/bin/black --extend-exclude=".*(\\.pyi|_pb2.py)$" --check .
|
||||
- /venv/bin/flake8 --extend-exclude="*.pyi,*_pb2.py" .
|
||||
- /venv/bin/mypy .
|
||||
- /venv/bin/flake8 .
|
||||
- /venv/bin/pytest -v .
|
||||
image: ${DOCKER_IMAGE_DEV}:${DOCKER_TAG}
|
||||
|
||||
test:cppcheck:
|
||||
|
|
|
@ -3,10 +3,6 @@ Upstream-Name: VILLASnode
|
|||
Upstream-Contact: Steffen Vogel <post@steffenvogel.de>
|
||||
Source: https://fein-aachen.org/en/projects/villas-node/
|
||||
|
||||
Files: *.vi *.opal *.dft *.sib *.json *.ipynb doc/pictures/* clients/opal/models/send_receive/eonerc_logo.png doc/favicon.png
|
||||
Copyright: 2018-2023, Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
License: Apache-2.0
|
||||
|
||||
Files: clients/rtds/**/*.txt clients/hypersim/*.ecf etc/labs/lab3.pcap packaging/live-iso/files/etc/* flake.lock tests/valgrind.supp packaging/archlinux/villas-node.install
|
||||
Files: *.vi *.opal *.dft *.sib *.json *.ipynb *_pb2.py doc/pictures/* doc/favicon.png clients/opal/models/send_receive/eonerc_logo.png clients/rtds/**/*.txt clients/hypersim/*.ecf etc/labs/lab3.pcap packaging/live-iso/files/etc/* flake.lock tests/valgrind.supp packaging/archlinux/villas-node.install
|
||||
Copyright: 2018-2023, Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
License: Apache-2.0
|
||||
|
|
|
@ -75,6 +75,7 @@ find_package(RDMACM)
|
|||
find_package(Etherlab)
|
||||
find_package(Lua)
|
||||
find_package(LibDataChannel)
|
||||
find_package(re)
|
||||
|
||||
# Check for tools
|
||||
find_program(PASTE NAMES paste)
|
||||
|
@ -117,13 +118,7 @@ pkg_check_modules(NANOMSG IMPORTED_TARGET nanomsg)
|
|||
if(NOT NANOMSG_FOUND)
|
||||
pkg_check_modules(NANOMSG IMPORTED_TARGET libnanomsg>=1.0.0)
|
||||
endif()
|
||||
pkg_check_modules(RE IMPORTED_TARGET re>=2.9.0)
|
||||
if(NOT RE_FOUND)
|
||||
pkg_check_modules(RE IMPORTED_TARGET libre>=2.9.0)
|
||||
endif()
|
||||
if(NOT RE_FOUND)
|
||||
pkg_check_modules(RE IMPORTED_TARGET re2)
|
||||
endif()
|
||||
|
||||
|
||||
if (REDISPP_FOUND)
|
||||
file(READ "${REDISPP_INCLUDEDIR}/sw/redis++/tls.h" CONTENTS)
|
||||
|
@ -199,7 +194,7 @@ cmake_dependent_option(WITH_NODE_NANOMSG "Build with nanomsg node-type"
|
|||
cmake_dependent_option(WITH_NODE_NGSI "Build with ngsi node-type" "${WITH_DEFAULTS}" "" OFF)
|
||||
cmake_dependent_option(WITH_NODE_OPAL "Build with opal node-type" "${WITH_DEFAULTS}" "Opal_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_NODE_REDIS "Build with redis node-type" "${WITH_DEFAULTS}" "HIREDIS_FOUND; REDISPP_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_NODE_RTP "Build with rtp node-type" "${WITH_DEFAULTS}" "RE_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_NODE_RTP "Build with rtp node-type" "${WITH_DEFAULTS}" "re_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_NODE_SHMEM "Build with shmem node-type" "${WITH_DEFAULTS}" "HAS_SEMAPHORE; HAS_MMAN" OFF)
|
||||
cmake_dependent_option(WITH_NODE_SIGNAL "Build with signal node-type" "${WITH_DEFAULTS}" "" OFF)
|
||||
cmake_dependent_option(WITH_NODE_SMU "Build with smu node-type" "${WITH_DEFAULTS}" "" OFF)
|
||||
|
|
33
CODEOWNERS
33
CODEOWNERS
|
@ -13,20 +13,27 @@
|
|||
# and not the global owner(s) will be requested for a review.
|
||||
|
||||
# FPGA
|
||||
fpga @n-eiling
|
||||
/lib/nodes/fpga.cpp @n-eiling
|
||||
/include/villas/nodes/fpga.hpp @n-eiling
|
||||
fpga @n-eiling
|
||||
/lib/nodes/fpga.cpp @n-eiling
|
||||
/include/villas/nodes/fpga.hpp @n-eiling
|
||||
/tools/hwdef-parse.py @n-eiling
|
||||
/tools/fpga-* @n-eiling
|
||||
/fpga @n-eiling
|
||||
/etc/examples/nodes/fpga.conf @n-eiling
|
||||
/etc/fpga @n-eiling
|
||||
/doc/openapi/components/schemas/nodes/fpga.yaml @n-eiling
|
||||
|
||||
|
||||
# PMU
|
||||
/lib/nodes/libiec61850_goose.cpp @windrad6
|
||||
/include/villas/nodes/libiec61850_goose.hpp @windrad6
|
||||
/lib/nodes/uldaq.cpp @windrad6
|
||||
/include/villas/nodes/uldaq.hpp @windrad6
|
||||
/lib/dumper.cpp @windrad6
|
||||
/include/villas/dumper.hpp @windrad6
|
||||
/lib/nodes/libiec61850_goose.cpp @windrad6
|
||||
/include/villas/nodes/libiec61850_goose.hpp @windrad6
|
||||
/lib/nodes/uldaq.cpp @windrad6
|
||||
/include/villas/nodes/uldaq.hpp @windrad6
|
||||
/lib/dumper.cpp @windrad6
|
||||
/include/villas/dumper.hpp @windrad6
|
||||
|
||||
# VFIO related files
|
||||
/common/lib/kernel/pci.cpp @n-eiling
|
||||
/common/lib/kernel/vfi_*.cpp @n-eiling
|
||||
/common/include/villas/kernel/pci.hpp @n-eiling
|
||||
/common/include/villas/kernel/vfio_*.hpp @n-eiling
|
||||
/common/lib/kernel/pci.cpp @n-eiling
|
||||
/common/lib/kernel/vfi_*.cpp @n-eiling
|
||||
/common/include/villas/kernel/pci.hpp @n-eiling
|
||||
/common/include/villas/kernel/vfio_*.hpp @n-eiling
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
// Count a value within its corresponding bucket.
|
||||
void put(double value);
|
||||
|
||||
// Calcluate the variance of all counted values.
|
||||
// Calculate the variance of all counted values.
|
||||
double getVar() const;
|
||||
|
||||
// Calculate the mean average of all counted values.
|
||||
|
@ -43,8 +43,8 @@ public:
|
|||
// Calculate the standard derivation of all counted values.
|
||||
double getStddev() const;
|
||||
|
||||
// Print all statistical properties of distribution including a graphilcal plot of the histogram.
|
||||
void print(Logger logger, bool details) const;
|
||||
// Print all statistical properties of distribution including a graphical plot of the histogram.
|
||||
void print(Logger logger, bool details, std::string prefix = "") const;
|
||||
|
||||
// Print ASCII style plot of histogram.
|
||||
void plot(Logger logger) const;
|
||||
|
@ -57,7 +57,7 @@ public:
|
|||
// Prints Matlab struct containing all infos to file.
|
||||
int dumpMatlab(FILE *f) const;
|
||||
|
||||
// Write the histogram in JSON format to fiel \p f.
|
||||
// Write the histogram in JSON format to file \p f.
|
||||
int dumpJson(FILE *f) const;
|
||||
|
||||
// Build a libjansson / JSON object of the histogram.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <villas/version.hpp>
|
||||
|
||||
|
|
|
@ -97,28 +97,28 @@ double Hist::getVar() const {
|
|||
|
||||
double Hist::getStddev() const { return sqrt(getVar()); }
|
||||
|
||||
void Hist::print(Logger logger, bool details) const {
|
||||
void Hist::print(Logger logger, bool details, std::string prefix) const {
|
||||
if (total > 0) {
|
||||
Hist::cnt_t missed = total - higher - lower;
|
||||
|
||||
logger->info("Counted values: {} ({} between {} and {})", total, missed,
|
||||
logger->info("{}Counted values: {} ({} between {} and {})", prefix, total, missed,
|
||||
low, high);
|
||||
logger->info("Highest: {:g}", highest);
|
||||
logger->info("Lowest: {:g}", lowest);
|
||||
logger->info("Mu: {:g}", getMean());
|
||||
logger->info("1/Mu: {:g}", 1.0 / getMean());
|
||||
logger->info("Variance: {:g}", getVar());
|
||||
logger->info("Stddev: {:g}", getStddev());
|
||||
logger->info("{}Highest: {:g}", prefix, highest);
|
||||
logger->info("{}Lowest: {:g}", prefix, lowest);
|
||||
logger->info("{}Mu: {:g}", prefix, getMean());
|
||||
logger->info("{}1/Mu: {:g}", prefix, 1.0 / getMean());
|
||||
logger->info("{}Variance: {:g}", prefix, getVar());
|
||||
logger->info("{}Stddev: {:g}", prefix, getStddev());
|
||||
|
||||
if (details && total - higher - lower > 0) {
|
||||
char *buf = dump();
|
||||
logger->info("Matlab: {}", buf);
|
||||
logger->info("{}Matlab: {}", prefix, buf);
|
||||
free(buf);
|
||||
|
||||
plot(logger);
|
||||
}
|
||||
} else
|
||||
logger->info("Counted values: {}", total);
|
||||
logger->info("{}Counted values: {}", prefix, total);
|
||||
}
|
||||
|
||||
void Hist::plot(Logger logger) const {
|
||||
|
@ -128,7 +128,7 @@ void Hist::plot(Logger logger) const {
|
|||
std::vector<TableColumn> cols = {
|
||||
{-9, TableColumn::Alignment::RIGHT, "Value", "%+9.3g"},
|
||||
{-6, TableColumn::Alignment::RIGHT, "Count", "%6ju"},
|
||||
{0, TableColumn::Alignment::LEFT, "Plot", "%s", "occurences"}};
|
||||
{0, TableColumn::Alignment::LEFT, "Plot", "%s", "occurrences"}};
|
||||
|
||||
Table table = Table(logger, cols);
|
||||
|
||||
|
|
|
@ -53,9 +53,6 @@ paths = (
|
|||
offset = 0,
|
||||
signals = ["f0", "f1", "f2", "f3"]
|
||||
}
|
||||
# {
|
||||
# type = "print"
|
||||
# }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -4,24 +4,21 @@
|
|||
# Please note, that using all options at the same time does not really
|
||||
# makes sense. The purpose of this example is to serve as a reference.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name = "villas-acs" # The name of this VILLASnode. Might by used by node-types
|
||||
# to identify themselves (default is the hostname).
|
||||
|
||||
# The name of this VILLASnode. Might by used by node-types
|
||||
# to identify themselves (default is the hostname)
|
||||
name = "villas-acs"
|
||||
|
||||
logging = {
|
||||
level = "debug"
|
||||
}
|
||||
|
||||
http = {
|
||||
port = 80 # Port for HTTP connections
|
||||
# Port for HTTP connections
|
||||
port = 80
|
||||
}
|
||||
|
||||
## Dictionary of nodes
|
||||
|
|
|
@ -4,10 +4,6 @@
|
|||
# Please note, that using all options at the same time does not really
|
||||
# makes sense. The purpose of this example is to serve as a reference.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
@ -19,5 +15,5 @@
|
|||
# An example node. Define multiple nodes in the "nodes" dictionary
|
||||
@include "nodes/socket.conf"
|
||||
|
||||
# A list of example paths. Define multiple paths by appending them to the "paths" list.
|
||||
# A list of example paths. Define multiple paths by appending them to the "paths" list
|
||||
@include "paths.conf"
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
# Global configuration file for VILLASnode.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
# Global configuration file for VILLASnode
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
|
@ -10,32 +6,39 @@
|
|||
|
||||
## Global Options
|
||||
|
||||
affinity = 0x01 # Mask of cores the server should run on
|
||||
# This also maps the NIC interrupts to those cores!
|
||||
# Mask of cores the server should run on
|
||||
# This also maps the NIC interrupts to those cores!
|
||||
affinity = 0x01
|
||||
|
||||
#priority = 50 # Priority for the server tasks.
|
||||
# Usually the server is using a real-time FIFO
|
||||
# scheduling algorithm
|
||||
# Priority for the server tasks
|
||||
# Usually the server is using a real-time FIFO
|
||||
# scheduling algorithm
|
||||
|
||||
# See: https://github.com/docker/docker/issues/22380
|
||||
# on why we cant use real-time scheduling in Docker
|
||||
# See: https://github.com/docker/docker/issues/22380
|
||||
# on why we cant use real-time scheduling in Docker
|
||||
#priority = 50
|
||||
|
||||
name = "villas-acs" # The name of this VILLASnode. Might by used by node-types
|
||||
# to identify themselves (default is the hostname).
|
||||
|
||||
# The name of this VILLASnode. Might by used by node-types
|
||||
# to identify themselves (default is the hostname)
|
||||
name = "villas-acs"
|
||||
|
||||
logging = {
|
||||
level = "debug" # The level of verbosity for debug messages
|
||||
# One of: "warn", "info", "error", "off", "info"
|
||||
# The level of verbosity for debug messages
|
||||
# One of: "warn", "info", "error", "off", "info"
|
||||
level = "debug"
|
||||
|
||||
# File for logs
|
||||
file = "/tmp/villas-node.log"
|
||||
|
||||
file = "/tmp/villas-node.log" # File for logs
|
||||
|
||||
syslog = true # Log to syslogd
|
||||
# Log to syslogd
|
||||
syslog = true
|
||||
}
|
||||
|
||||
http = {
|
||||
enabled = true, # Do not listen on port if true
|
||||
# Do not listen on port if true
|
||||
enabled = true,
|
||||
|
||||
port = 80 # Port for HTTP connections
|
||||
# Port for HTTP connections
|
||||
port = 80
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ paths = (
|
|||
out = "file_node"
|
||||
|
||||
hooks = (
|
||||
# Use a frame hook to generate NEW_FRAME annotations.
|
||||
# Use a frame hook to generate NEW_FRAME annotations
|
||||
"frame",
|
||||
{
|
||||
type = "digest"
|
||||
|
|
|
@ -13,8 +13,8 @@ paths = (
|
|||
type = "dp"
|
||||
|
||||
signal = "sine"
|
||||
f0 = 50 # Hz
|
||||
dt = 0.1 # seconds
|
||||
f0 = 50 # In Hz
|
||||
dt = 0.1 # In seconds
|
||||
|
||||
# Alternative to dt
|
||||
# rate = 10 Hz
|
||||
|
|
|
@ -17,8 +17,8 @@ paths = (
|
|||
threshold = 0.5
|
||||
|
||||
# Once triggered, keep active for:
|
||||
duration = 5 # in seconds
|
||||
samples = 100 # in number of samples
|
||||
duration = 5 # In seconds
|
||||
samples = 100 # In number of samples
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,14 +16,23 @@ paths = (
|
|||
"sine"
|
||||
)
|
||||
|
||||
sample_rate = 1000, # sample rate of the input signal
|
||||
dft_rate = 10, # number of phasors calculated per second
|
||||
# Sample rate of the input signal
|
||||
sample_rate = 1000,
|
||||
|
||||
estimation_range = 10, # the range around the nominal_freq in with the estimation is done
|
||||
nominal_freq = 50, # the nominal grid frequnecy
|
||||
number_plc = 10., # the number of power line cylces stored in the buffer
|
||||
# Number of phasors calculated per second
|
||||
dft_rate = 10,
|
||||
|
||||
angle_unit = "rad" # one of: rad, degree
|
||||
# Yhe range around the nominal_freq in with the estimation is done
|
||||
estimation_range = 10,
|
||||
|
||||
# Yhe nominal grid frequnecy
|
||||
nominal_freq = 50,
|
||||
|
||||
# Yhe number of power line cylces stored in the buffer
|
||||
number_plc = 10.,
|
||||
|
||||
# One of: rad, degree
|
||||
angle_unit = "rad"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -15,12 +15,12 @@ paths = (
|
|||
type = "lua"
|
||||
|
||||
# Enables or disables the use of signal names in the process() function
|
||||
# of the Lua script. If disabled, numeric indices will be used.
|
||||
# of the Lua script. If disabled, numeric indices will be used
|
||||
use_names = true
|
||||
|
||||
# The Lua hook will pass the complete hook configuration to the prepare()
|
||||
# function. So you can add arbitrary settings here which are then
|
||||
# consumed by the Lua script.
|
||||
# consumed by the Lua script
|
||||
some_setting = "Hello World"
|
||||
this = {
|
||||
is = {
|
||||
|
@ -39,14 +39,14 @@ paths = (
|
|||
#
|
||||
# stop() Called when the node/path is stopped
|
||||
#
|
||||
# restart() Called when the node/path is restarted.
|
||||
# Falls back to stop() + start() if absent.
|
||||
# restart() Called when the node/path is restarted
|
||||
# Falls back to stop() + start() if absent
|
||||
#
|
||||
# process(smp) Called for each sample which is being processed.
|
||||
# process(smp) Called for each sample which is being processed
|
||||
# The sample is passed as a Lua table with the following
|
||||
# fields:
|
||||
# - sequence The sequence number of the sample.
|
||||
# - flags The flags field of the sample.
|
||||
# - sequence The sequence number of the sample
|
||||
# - flags The flags field of the sample
|
||||
# - ts_origin The origin timestamp as a Lua table containing
|
||||
# the following keys:
|
||||
# 0: seconds
|
||||
|
@ -57,14 +57,14 @@ paths = (
|
|||
# 1: nanoseconds
|
||||
# - data The sample data as a Lua table container either
|
||||
# numeric indices or the signal names depending
|
||||
# on the 'use_names' option of the hook.
|
||||
# on the 'use_names' option of the hook
|
||||
#
|
||||
# periodic() Called periodically with the rate of the global 'stats' option.
|
||||
# periodic() Called periodically with the rate of the global 'stats' option
|
||||
script = "../lua/hooks/test.lua"
|
||||
|
||||
# Expression mode: We provide a mangled signal list including Lua expressions
|
||||
signals = (
|
||||
{ name = "sum", type="float", unit = "V", expression = "smp.data.square * 10" },
|
||||
{ name = "sum", type="float", unit = "V", expression = "smp.data.square * 10" },
|
||||
|
||||
# You can access any global variable set by the script
|
||||
{ name = "sequence", type="float", unit = "V", expression = "global_var" },
|
||||
|
@ -76,7 +76,7 @@ paths = (
|
|||
{ name = "sum", type="float", unit = "V", expression = "math.sin(2 * math.pi * f * t)" },
|
||||
|
||||
{ name = "random", expression = "smp.data.random" }
|
||||
)
|
||||
)
|
||||
},
|
||||
{
|
||||
type = "print"
|
||||
|
|
|
@ -16,13 +16,20 @@ paths = (
|
|||
"sine"
|
||||
)
|
||||
|
||||
sample_rate = 1000, # sample rate of the input signal
|
||||
dft_rate = 10, # number of phasors calculated per second
|
||||
# Sample rate of the input signal
|
||||
sample_rate = 1000,
|
||||
|
||||
nominal_freq = 50, # the nominal grid frequnecy
|
||||
number_plc = 10., # the number of power line cylces stored in the buffer
|
||||
# Number of phasors calculated per second
|
||||
dft_rate = 10,
|
||||
|
||||
angle_unit = "rad" # one of: rad, degree
|
||||
# The nominal grid frequnecy
|
||||
nominal_freq = 50,
|
||||
|
||||
# The number of power line cylces stored in the buffer
|
||||
number_plc = 10.,
|
||||
|
||||
# One of: rad, degree
|
||||
angle_unit = "rad"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,21 +16,38 @@ paths = (
|
|||
"sine"
|
||||
)
|
||||
|
||||
sample_rate = 1000, # sample rate of the input signal
|
||||
dft_rate = 10, # number of phasors calculated per second
|
||||
# Sample rate of the input signal
|
||||
sample_rate = 1000,
|
||||
|
||||
start_frequency = 49.7, # lowest frequency bin
|
||||
end_frequency = 50.3, # highest frequency bin
|
||||
frequency_resolution = 0.1, # frequency bin resolution
|
||||
# Number of phasors calculated per second
|
||||
dft_rate = 10,
|
||||
|
||||
window_size_factor = 1, # a factor with which the window will be increased
|
||||
window_type = "hamming", # one of: flattop, hamming, hann
|
||||
padding_type = "zero", # one of: signal_repeat, zero
|
||||
frequency_estimate_type = "quadratic", # one of: quadratic
|
||||
# Lowest frequency bin
|
||||
start_frequency = 49.7,
|
||||
|
||||
pps_index = 0, # signal index of the PPS signal
|
||||
# Highest frequency bin
|
||||
end_frequency = 50.3,
|
||||
|
||||
angle_unit = "rad" # one of: rad, degree
|
||||
# Frequency bin resolution
|
||||
frequency_resolution = 0.1,
|
||||
|
||||
# A factor with which the window will be increased
|
||||
window_size_factor = 1,
|
||||
|
||||
# One of: flattop, hamming, hann
|
||||
window_type = "hamming",
|
||||
|
||||
# One of: signal_repeat, zero
|
||||
padding_type = "zero",
|
||||
|
||||
# One of: quadratic
|
||||
frequency_estimate_type = "quadratic",
|
||||
|
||||
# Signal index of the PPS signal
|
||||
pps_index = 0,
|
||||
|
||||
# One of: rad, degree
|
||||
angle_unit = "rad"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ paths = (
|
|||
|
||||
output = "print_output_file.log"
|
||||
format = "villas.human"
|
||||
# prefix = "[file_node] " # prefix and output are exclusive settings!
|
||||
# prefix = "[file_node] " # Prefix and output are exclusive settings!
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,16 +8,25 @@ nodes = {
|
|||
in = {
|
||||
signals = (
|
||||
{
|
||||
name = "" # Same as 'id' in uAPI context
|
||||
description = "Volts on Bus A" # A human readable description of the channel
|
||||
type = "float" # Same as 'datatype' in uAPI context
|
||||
# Same as 'id' in uAPI context
|
||||
name = ""
|
||||
|
||||
# A human readable description of the channel
|
||||
description = "Volts on Bus A"
|
||||
|
||||
# Same as 'datatype' in uAPI context
|
||||
type = "float"
|
||||
unit = "V"
|
||||
payload = "events" # or 'samples'
|
||||
rate = 100.0 # An expected refresh/sample rate of the signal
|
||||
payload = "events" # Or 'samples'
|
||||
|
||||
# An expected refresh/sample rate of the signal
|
||||
rate = 100.0
|
||||
|
||||
range = {
|
||||
min = 20.0
|
||||
max = 100.0
|
||||
}
|
||||
|
||||
readable = true
|
||||
writable = false
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ nodes = {
|
|||
rate = 1000,
|
||||
|
||||
signals = (
|
||||
# note: order in this array defines order in villas sample
|
||||
# Note: order in this array defines order in villas sample
|
||||
{ channel = 0, range = 0, aref = 0, name = "temperature_int" },
|
||||
{ channel = 1, range = 0, aref = 0, name = "loopback_ao0" },
|
||||
{ channel = 2, range = 0, aref = 0, name = "loopback_ao1" },
|
||||
|
@ -23,11 +23,11 @@ nodes = {
|
|||
# Note: buffer size and rate shouldn't be changed at the moment
|
||||
# output sample rate
|
||||
rate = 40000,
|
||||
# comedi write buffer in kilobytes
|
||||
# Comedi write buffer in kilobytes
|
||||
bufsize = 24,
|
||||
|
||||
signals = (
|
||||
# note: order in this array corresponds to order in villas sample
|
||||
# Note: order in this array corresponds to order in villas sample
|
||||
{ name = "ao0", channel = 0, range = 0, aref = 0 },
|
||||
{ name = "ao1", channel = 1, range = 0, aref = 0 },
|
||||
{ name = "ao2", channel = 2, range = 0, aref = 0 },
|
||||
|
@ -69,10 +69,10 @@ nodes = {
|
|||
paths = (
|
||||
# 2-ch sine
|
||||
# {
|
||||
# in = [ "sine1.data[0]", "sine2.data[0]" ]
|
||||
# out = "pcie6259"
|
||||
# rate = 10000
|
||||
# mask = ()
|
||||
# in = [ "sine1.data[0]", "sine2.data[0]" ]
|
||||
# out = "pcie6259"
|
||||
# rate = 10000
|
||||
# mask = ()
|
||||
# }
|
||||
|
||||
# Remote data via UDP
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
ethercat = {
|
||||
coupler = {
|
||||
position = 0
|
||||
vendor_id = 0x00000002 # Backhoff
|
||||
vendor_id = 0x00000002 # Beckhoff
|
||||
product_code = 0x044c2c52 # EK1100
|
||||
}
|
||||
|
||||
|
|
|
@ -3,31 +3,40 @@
|
|||
|
||||
nodes = {
|
||||
file_node = {
|
||||
type = "file"
|
||||
type = "file"
|
||||
|
||||
### The following settings are specific to the file node-type!! ###
|
||||
|
||||
uri = "logs/input.log", # These options specify the URI where the the files are stored
|
||||
#uri = "logs/output_%F_%T.log" # The URI accepts all format tokens of (see strftime(3))
|
||||
# These options specify the URI where the the files are stored
|
||||
# The URI accepts all format tokens of (see strftime(3))
|
||||
uri = "logs/input.log",
|
||||
# uri = "logs/output_%F_%T.log"
|
||||
|
||||
format = "csv"
|
||||
|
||||
in = {
|
||||
epoch_mode = "direct" # One of: direct (default), wait, relative, absolute
|
||||
epoch = 10 # The interpretation of this value depends on epoch_mode (default is 0).
|
||||
# Consult the documentation of a full explanation
|
||||
# One of: direct (default), wait, relative, absolute
|
||||
epoch_mode = "direct"
|
||||
|
||||
rate = 2.0 # A constant rate at which the lines of the input files should be read
|
||||
# A missing or zero value will use the timestamp in the first column
|
||||
# of the file to determine the pause between consecutive lines.
|
||||
eof = "rewind" # Rewind the file and start from the beginning.
|
||||
# The interpretation of this value depends on epoch_mode (default is 0)
|
||||
# Consult the documentation of a full explanation
|
||||
epoch = 10
|
||||
|
||||
buffer_size = 0 # Creates a stream buffer if value is positive
|
||||
# A constant rate at which the lines of the input files should be read
|
||||
# A missing or zero value will use the timestamp in the first column
|
||||
# of the file to determine the pause between consecutive lines
|
||||
rate = 2.0
|
||||
|
||||
# Rewind the file and start from the beginning
|
||||
eof = "rewind"
|
||||
|
||||
# Creates a stream buffer if value is positive
|
||||
buffer_size = 0
|
||||
},
|
||||
out = {
|
||||
flush = false # Flush or upload contents of the file every time new samples are sent.
|
||||
# Flush or upload contents of the file every time new samples are sent
|
||||
flush = false
|
||||
|
||||
buffer_size = 0 # Creates a stream buffer if value is positive
|
||||
# Creates a stream buffer if value is positive
|
||||
buffer_size = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
nodes = {
|
||||
iec104_node_seq = {
|
||||
iec104_node_seq = {
|
||||
type = "iec60870-5-104"
|
||||
address = "0.0.0.0"
|
||||
port = 2404
|
||||
|
@ -18,7 +18,7 @@ nodes = {
|
|||
# Interpret the duplicate IOAs as a sequence by incrementing the
|
||||
# IOA with each duplication. This only applies to two adjacent
|
||||
# signals with the same IOA. Specifying an IOA twice with other
|
||||
# IOAs inbetween is an error.
|
||||
# IOAs inbetween is an error
|
||||
duplicate_ioa_is_sequence = true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
|
||||
nodes = {
|
||||
iec104_node = {
|
||||
iec104_node = {
|
||||
type = "iec60870-5-104"
|
||||
|
||||
# Network address and port of the server
|
||||
|
@ -22,14 +22,16 @@ nodes = {
|
|||
# Map signals to information object addresses and ASDU data types
|
||||
# one ASDU per specified asdu_type_id/asdu_type+with_timestamp is
|
||||
# send for each sample. Signals of the same type are collected
|
||||
# in a single ASDU.
|
||||
# in a single ASDU
|
||||
signals = (
|
||||
{
|
||||
# The ASDU data type
|
||||
asdu_type = "normalized-float"
|
||||
# add 56 bit unix timestamp to ASDU
|
||||
|
||||
# Add 56 bit unix timestamp to ASDU
|
||||
with_timestamp = false
|
||||
# the information object address of this signal
|
||||
|
||||
# The information object address of this signal
|
||||
ioa = 4202832
|
||||
},
|
||||
{
|
||||
|
|
|
@ -3,9 +3,14 @@
|
|||
|
||||
nodes = {
|
||||
loopback_node = {
|
||||
type = "loopback", # A loopback node will receive exactly the same data which has been sent to it.
|
||||
# The internal implementation is based on queue.
|
||||
queuelen = 1024, # The queue length of the internal queue which buffers the samples.
|
||||
mode = "polling" # Use busy polling for synchronization of the read and write side of the queue
|
||||
# A loopback node will receive exactly the same data which has been sent to it
|
||||
type = "loopback",
|
||||
|
||||
# The internal implementation is based on queue
|
||||
# The queue length of the internal queue which buffers the samples
|
||||
queuelen = 1024,
|
||||
|
||||
# Use busy polling for synchronization of the read and write side of the queue
|
||||
mode = "polling"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,20 +8,20 @@ nodes = {
|
|||
# Required transport type. Can be either "rtu" or "tcp"
|
||||
transport = "tcp"
|
||||
|
||||
# Optional timeout in seconds when waiting for responses from a modbus server.
|
||||
# Default is 1.0.
|
||||
# Optional timeout in seconds when waiting for responses from a modbus server
|
||||
# Default is 1.0
|
||||
response_timeout = 1.0
|
||||
|
||||
|
||||
#
|
||||
# Settings for transport = "tcp".
|
||||
# Settings for transport = "tcp"
|
||||
#
|
||||
|
||||
# Required remote IP address.
|
||||
# Required remote IP address
|
||||
remote = "127.0.0.1"
|
||||
|
||||
# Optional remote port.
|
||||
# Default is 502.
|
||||
# Optional remote port
|
||||
# Default is 502
|
||||
port = 502
|
||||
|
||||
|
||||
|
@ -29,10 +29,10 @@ nodes = {
|
|||
# Settings for transport = "rtu"
|
||||
#
|
||||
|
||||
# Required device file.
|
||||
# Required device file
|
||||
device = "/dev/ttyS0"
|
||||
|
||||
# Required baudrate.
|
||||
# Required baudrate
|
||||
baudrate = 9600
|
||||
|
||||
# Required parity. One of "none", "even" and "odd"
|
||||
|
@ -44,102 +44,102 @@ nodes = {
|
|||
# Required stop bits. One of 1, 2
|
||||
stop_bits = 1
|
||||
|
||||
# The modbus unit ID.
|
||||
# Required for transport = "rtu".
|
||||
# Optional for transport = "tcp".
|
||||
# The modbus unit ID
|
||||
# Required for transport = "rtu"
|
||||
# Optional for transport = "tcp"
|
||||
unit = 1
|
||||
|
||||
# Optional polling rate for the modbus remote reads.
|
||||
# Defaults to 10.
|
||||
# Optional polling rate for the modbus remote reads
|
||||
# Defaults to 10
|
||||
rate = 10
|
||||
|
||||
in = {
|
||||
signals = (
|
||||
# A 32-bit IEEE 754 floating point value.
|
||||
# This spans 2 registers.
|
||||
# A 32-bit IEEE 754 floating point value
|
||||
# This spans 2 registers
|
||||
{
|
||||
# Required type = "float".
|
||||
# Required type = "float"
|
||||
type = "float"
|
||||
|
||||
# Required address of the lowest register.
|
||||
# Required address of the lowest register
|
||||
address = 0x50
|
||||
|
||||
# Optional endianess for joining the 2 16-bit registers into a 32-bit value.
|
||||
# Defaults to "big".
|
||||
# Optional endianess for joining the 2 16-bit registers into a 32-bit value
|
||||
# Defaults to "big"
|
||||
word_endianess = "big"
|
||||
|
||||
# Optional endianess for the 2 bytes within a register.
|
||||
# Defaults to "big".
|
||||
# Optional endianess for the 2 bytes within a register
|
||||
# Defaults to "big"
|
||||
byte_endianess = "big"
|
||||
|
||||
# Optional scale that should be applied to the integer value.
|
||||
# Defaults to 1.
|
||||
# Optional scale that should be applied to the integer value
|
||||
# Defaults to 1
|
||||
scale = 10
|
||||
|
||||
# Optional offset that should be applied to the integer value after scaling.
|
||||
# Defaults to 0.
|
||||
# Optional offset that should be applied to the integer value after scaling
|
||||
# Defaults to 0
|
||||
offset = 2
|
||||
},
|
||||
# A single bit within a register as a boolean value.
|
||||
# A single bit within a register as a boolean value
|
||||
{
|
||||
# Required type = "boolean".
|
||||
# Required type = "boolean"
|
||||
type = "boolean"
|
||||
|
||||
# Required address of the register.
|
||||
# Required address of the register
|
||||
address = 0x54
|
||||
|
||||
# Required bit within the register.
|
||||
# Starting at 0.
|
||||
# Required bit within the register
|
||||
# Starting at 0
|
||||
bit = 0
|
||||
},
|
||||
# An integer value.
|
||||
# This may span multiple registers.
|
||||
# An integer value
|
||||
# This may span multiple registers
|
||||
{
|
||||
# Required type = "integer".
|
||||
# Required type = "integer"
|
||||
type = "integer"
|
||||
|
||||
# Required address of the lowest register.
|
||||
# Required address of the lowest register
|
||||
address = 0x52
|
||||
|
||||
# Optional number of registers that should be joined to form the value.
|
||||
# Defaults to 1.
|
||||
# Optional number of registers that should be joined to form the value
|
||||
# Defaults to 1
|
||||
integer_registers = 1
|
||||
|
||||
# Optional endianess for joining the 16-bit registers into a 32-bit value.
|
||||
# Defaults to "big".
|
||||
# Optional endianess for joining the 16-bit registers into a 32-bit value
|
||||
# Defaults to "big"
|
||||
word_endianess = "big"
|
||||
|
||||
# Optional endianess for the 2 bytes within a register.
|
||||
# Defaults to "big".
|
||||
# Optional endianess for the 2 bytes within a register
|
||||
# Defaults to "big"
|
||||
byte_endianess = "big"
|
||||
},
|
||||
# An float value created by reading an integer and applying an optional offset and scale.
|
||||
# This may span multiple registers.
|
||||
# An float value created by reading an integer and applying an optional offset and scale
|
||||
# This may span multiple registers
|
||||
{
|
||||
# Required type = "float".
|
||||
# Required type = "float"
|
||||
type = "float"
|
||||
|
||||
# Required address of the lowest register.
|
||||
# Required address of the lowest register
|
||||
address = 0x52
|
||||
|
||||
# Required number of registers that should be joined to form the value.
|
||||
# A "float" value without the "integer_registers" settings is considered an IEEE 754 float, spanning 2 registers.
|
||||
# Required number of registers that should be joined to form the value
|
||||
# A "float" value without the "integer_registers" settings is considered an IEEE 754 float, spanning 2 registers
|
||||
integer_registers = 1
|
||||
|
||||
# Optional endianess for joining the 16-bit registers into a 32-bit value.
|
||||
# Defaults to "big".
|
||||
# Optional endianess for joining the 16-bit registers into a 32-bit value
|
||||
# Defaults to "big"
|
||||
word_endianess = "big"
|
||||
|
||||
# Optional endianess for the 2 bytes within a register.
|
||||
# Defaults to "big".
|
||||
# Optional endianess for the 2 bytes within a register
|
||||
# Defaults to "big"
|
||||
byte_endianess = "big"
|
||||
|
||||
# Optional scale that should be applied to the integer value.
|
||||
# Defaults to 1.
|
||||
# Optional scale that should be applied to the integer value
|
||||
# Defaults to 1
|
||||
scale = 10
|
||||
|
||||
# Optional offset that should be applied to the integer value after scaling.
|
||||
# Defaults to 0.
|
||||
# Optional offset that should be applied to the integer value after scaling
|
||||
# Defaults to 0
|
||||
offset = 2
|
||||
}
|
||||
)
|
||||
|
@ -147,18 +147,18 @@ nodes = {
|
|||
|
||||
out = {
|
||||
signals = (
|
||||
# All register mappings described for "in" except for "boolean" are supported in the "out" signals.
|
||||
# All register mappings described for "in" except for "boolean" are supported in the "out" signals
|
||||
{
|
||||
type = "float"
|
||||
address = 0x50
|
||||
|
||||
# Scale and offset a applied as attributes of the register that is written to.
|
||||
# Scale and offset a applied as attributes of the register that is written to
|
||||
# This means the value written to "register" for a "signal" with "offset" and "scale" will be:
|
||||
#
|
||||
# register = (signal - offset) / scale
|
||||
#
|
||||
# It is fairly common to specify a scale and offset for modbus registers in a device manual.
|
||||
# You should be able to plug those values into this configuration without conversion.
|
||||
# It is fairly common to specify a scale and offset for modbus registers in a device manual
|
||||
# You should be able to plug those values into this configuration without conversion
|
||||
scale = 10
|
||||
offset = 2
|
||||
},
|
||||
|
|
|
@ -12,7 +12,8 @@ nodes = {
|
|||
host = "localhost",
|
||||
port = 1883,
|
||||
|
||||
keepalive = 5, # Send ping every 5 seconds to keep connection alive
|
||||
# Send ping every 5 seconds to keep connection alive
|
||||
keepalive = 5,
|
||||
retain = false,
|
||||
qos = 0,
|
||||
|
||||
|
|
|
@ -7,9 +7,14 @@ nodes = {
|
|||
|
||||
out = {
|
||||
endpoints = [
|
||||
"tcp://*:12000", # TCP socket
|
||||
"ipc:///tmp/test.ipc", # Interprocess communication
|
||||
"inproc://test" # Inprocess communication
|
||||
# TCP socket
|
||||
"tcp://*:12000",
|
||||
|
||||
# Interprocess communication
|
||||
"ipc:///tmp/test.ipc",
|
||||
|
||||
# Inprocess communication
|
||||
"inproc://test"
|
||||
],
|
||||
}
|
||||
in = {
|
||||
|
|
|
@ -2,28 +2,39 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
nodes = {
|
||||
udp_node = { # The dictionary is indexed by the name of the node.
|
||||
type = "socket", # For a list of available node-types run: 'villas-node -h'
|
||||
udp_node = {
|
||||
type = "socket",
|
||||
|
||||
### The following settings are specific to the socket node-type!! ###
|
||||
|
||||
format = "gtnet", # For a list of available node-types run: 'villas-node -h'
|
||||
format = "gtnet",
|
||||
|
||||
in = {
|
||||
address = "127.0.0.1:12001" # This node only received messages on this IP:Port pair
|
||||
address = "127.0.0.1:12001"
|
||||
},
|
||||
out = {
|
||||
address = "127.0.0.1:12000", # This node sends outgoing messages to this IP:Port pair
|
||||
address = "127.0.0.1:12000",
|
||||
|
||||
netem = { # Network emulation settings
|
||||
# Network emulation settings
|
||||
# Those settings can be specified for each node individually!
|
||||
netem = {
|
||||
enabled = true,
|
||||
# Those settings can be specified for each node individually!
|
||||
delay = 100000, # Additional latency in microseconds
|
||||
jitter = 30000, # Jitter in uS
|
||||
distribution = "normal", # Distribution of delay: uniform, normal, pareto, paretonormal
|
||||
loss = 10 # Packet loss in percent
|
||||
duplicate = 10, # Duplication in percent
|
||||
corrupt = 10 # Corruption in percent
|
||||
|
||||
# Additional latency in microseconds
|
||||
delay = 100000,
|
||||
|
||||
# Jitter in uS
|
||||
jitter = 30000,
|
||||
|
||||
# Distribution of delay: uniform, normal, pareto, paretonormal
|
||||
distribution = "normal",
|
||||
|
||||
# Packet loss in percent
|
||||
loss = 10
|
||||
|
||||
# Duplication in percent
|
||||
duplicate = 10,
|
||||
|
||||
# Corruption in percent
|
||||
corrupt = 10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,28 +5,33 @@ nodes = {
|
|||
ngsi_node = {
|
||||
type = "ngsi",
|
||||
|
||||
### The following settings are specific to the ngsi node-type!! ###
|
||||
|
||||
# The HTTP REST API endpoint of the FIRWARE context broker
|
||||
endpoint = "http://46.101.131.212:1026",
|
||||
|
||||
access_token: "aig1aaQuohsh5pee9uiC2Bae3loSh9wu" # Add an 'Auth-Token' token header to each request
|
||||
# Add an 'Auth-Token' token header to each request
|
||||
access_token = "aig1aaQuohsh5pee9uiC2Bae3loSh9wu"
|
||||
|
||||
entity_id = "S3_ElectricalGrid",
|
||||
entity_type = "ElectricalGridMonitoring",
|
||||
|
||||
create = true # Create the NGSI entities during startup
|
||||
# Create the NGSI entities during startup
|
||||
create = true
|
||||
|
||||
rate = 0.1 # Rate at which we poll the broker for updates
|
||||
timeout = 1, # Timeout of HTTP request in seconds (default is 1, must be smaller than 1 / rate)
|
||||
verify_ssl = false, # Verification of SSL server certificates (default is true)
|
||||
# Rate at which we poll the broker for updates
|
||||
rate = 0.1
|
||||
|
||||
# Timeout of HTTP request in seconds (default is 1, must be smaller than 1 / rate)
|
||||
timeout = 1,
|
||||
|
||||
# Verification of SSL server certificates (default is true)
|
||||
verify_ssl = false,
|
||||
|
||||
in = {
|
||||
signals = (
|
||||
{
|
||||
name = "attr1",
|
||||
ngsi_attribute_name = "attr1", # defaults to signal 'name'
|
||||
ngsi_attribute_type = "Volts", # default to signal 'unit'
|
||||
ngsi_attribute_name = "attr1", # Defaults to signal 'name'
|
||||
ngsi_attribute_type = "Volts", # Default to signal 'unit'
|
||||
ngsi_attribute_metadatas = (
|
||||
{ name="accuracy", type="percent", value="5" }
|
||||
)
|
||||
|
|
|
@ -2,38 +2,17 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
nodes = {
|
||||
opal_node = { # The server can be started as an Asynchronous process
|
||||
type = "opal", # from within an OPAL-RT model.
|
||||
# The server can be started as an Asynchronous process
|
||||
# from within an OPAL-RT model
|
||||
opal_node = {
|
||||
type = "opal",
|
||||
|
||||
### The following settings are specific to the opal node-type!! ###
|
||||
# It's possible to have multiple send / recv Icons per model
|
||||
send_id = 1,
|
||||
|
||||
# Specify the ID here
|
||||
recv_id = 1,
|
||||
|
||||
send_id = 1, # It's possible to have multiple send / recv Icons per model
|
||||
recv_id = 1, # Specify the ID here.
|
||||
reply = true
|
||||
},
|
||||
file_node = {
|
||||
type = "file",
|
||||
|
||||
### The following settings are specific to the file node-type!! ###
|
||||
|
||||
uri = "logs/input.log", # These options specify the path prefix where the the files are stored
|
||||
|
||||
in = {
|
||||
epoch_mode = "direct" # One of: direct (default), wait, relative, absolute
|
||||
epoch = 10 # The interpretation of this value depends on epoch_mode (default is 0).
|
||||
# Consult the documentation of a full explanation
|
||||
|
||||
rate = 2.0 # A constant rate at which the lines of the input files should be read
|
||||
# A missing or zero value will use the timestamp in the first column
|
||||
# of the file to determine the pause between consecutive lines.
|
||||
|
||||
buffer_size = 1000000
|
||||
|
||||
eof = "rewind" # One of: rewind, exit (default) or wait
|
||||
},
|
||||
out = {
|
||||
flush = true
|
||||
buffer_size = 1000000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,25 +5,36 @@ nodes = {
|
|||
redis_node = {
|
||||
type = "redis",
|
||||
|
||||
format = "json", # only valid for mode = 'channel' and 'key'
|
||||
# With mode = 'hash' we will use a simple human readable format
|
||||
# Only valid for mode = 'channel' and 'key'
|
||||
# With mode = 'hash' we will use a simple human readable format
|
||||
format = "json",
|
||||
|
||||
key = "my_key" # The Redis key to be used for mode = 'key' or 'hash' (default is the node name)
|
||||
channel = "my_channel" # the Redis channel tp be used for mode = 'channel' (default is the node name)
|
||||
# The Redis key to be used for mode = 'key' or 'hash' (default is the node name)
|
||||
key = "my_key"
|
||||
|
||||
mode = "key", # one of:
|
||||
# - 'channel' (publish/subscribe)
|
||||
# - 'key' (set/get)
|
||||
# - 'hash' (hmset/hgetall)
|
||||
# The Redis channel tp be used for mode = 'channel' (default is the node name)
|
||||
channel = "my_channel"
|
||||
|
||||
notify = false # Whether or not to use Redis keyspace event notifications to get notified about updates
|
||||
# One of:
|
||||
# - 'channel' (publish/subscribe)
|
||||
# - 'key' (set/get)
|
||||
# - 'hash' (hmset/hgetall)
|
||||
mode = "key",
|
||||
|
||||
rate = 1.0 # The polling rate when notify = false
|
||||
# Whether or not to use Redis keyspace event notifications to get notified about updates
|
||||
notify = false
|
||||
|
||||
uri = "tcp://localhost:6379/0", # The Redis connection URI
|
||||
# The polling rate when notify = false
|
||||
rate = 1.0
|
||||
|
||||
# host = "localhost" # Alternatively the connection options can be specified independently
|
||||
# port = 6379 # Note: options here will overwrite the respective part of the URI if both are given.
|
||||
# The Redis connection URI
|
||||
uri = "tcp://localhost:6379/0",
|
||||
|
||||
# Alternatively the connection options can be specified independently
|
||||
# host = "localhost"
|
||||
|
||||
# Note: options here will overwrite the respective part of the URI if both are given
|
||||
# port = 6379
|
||||
# db = 0
|
||||
|
||||
# path = "/var/run/redis.sock"
|
||||
|
@ -32,11 +43,11 @@ nodes = {
|
|||
# password = "guest"
|
||||
|
||||
# ssl = {
|
||||
# enabled: true
|
||||
# cacert: "/etc/ssl/certs/ca-certificates.crt",
|
||||
# cacertdir: "/etc/ssl/certs"
|
||||
# cert: "./my_cert.crt",
|
||||
# key, "./my_key.key"
|
||||
# enabled = true
|
||||
# cacert = "/etc/ssl/certs/ca-certificates.crt",
|
||||
# cacertdir = "/etc/ssl/certs"
|
||||
# cert = "./my_cert.crt",
|
||||
# key = "./my_key.key"
|
||||
# }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,11 +41,15 @@ nodes = {
|
|||
out = {
|
||||
address = "127.0.0.1:12000"
|
||||
|
||||
netem = { # Network emulation settings
|
||||
# Network emulation settings
|
||||
netem = {
|
||||
enabled = false,
|
||||
|
||||
delay = 100000, # Additional latency in microseconds
|
||||
loss = 10 # Packet loss in percent
|
||||
# Additional latency in microseconds
|
||||
delay = 100000,
|
||||
|
||||
# Packet loss in percent
|
||||
loss = 10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,18 +6,23 @@ nodes = {
|
|||
type = "shmem",
|
||||
|
||||
in = {
|
||||
# Name of shared memory segment for receiving side
|
||||
name = "sn1_in"
|
||||
}, # Name of shared memory segment for receiving side
|
||||
},
|
||||
out = {
|
||||
name = "sn1_in" # Name of shared memory segment for sending side
|
||||
# Name of shared memory segment for sending side
|
||||
name = "sn1_in"
|
||||
},
|
||||
|
||||
queuelen = 1024, # Length of the queues
|
||||
mode = "pthread", # We can busy-wait or use pthread condition variables for synchronizations
|
||||
# Length of the queues
|
||||
queuelen = 1024,
|
||||
|
||||
# We can busy-wait or use pthread condition variables for synchronizations
|
||||
mode = "pthread",
|
||||
|
||||
# Execute an external process when starting the node which
|
||||
# then starts the other side of this shared memory channel
|
||||
# Usually we also pass the shmem names as parameters.
|
||||
# Usually we also pass the shmem names as parameters
|
||||
exec = [ "villas-shmem", "sn1_in", "sn1_out" ]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,15 @@ nodes = {
|
|||
type = "signal.v2",
|
||||
|
||||
rate = 10.0
|
||||
realtime = true, # Wait between emitting each sample
|
||||
limit = 1000, # Only emit 1000 samples, then stop
|
||||
monitor_missed = true # Count and warn about missed steps
|
||||
|
||||
# Wait between emitting each sample
|
||||
realtime = true,
|
||||
|
||||
# Only emit 1000 samples, then stop
|
||||
limit = 1000,
|
||||
|
||||
# Count and warn about missed steps
|
||||
monitor_missed = true
|
||||
|
||||
in = {
|
||||
signals = (
|
||||
|
|
|
@ -8,14 +8,31 @@ nodes = {
|
|||
# One of "sine", "square", "ramp", "triangle", "random", "mixed", "counter"
|
||||
signal = [ "sine", "pulse", "square" ],
|
||||
|
||||
values = 3, # Number of values per sample
|
||||
amplitude = [ 1.2, 0.0, 4.0 ], # Amplitude of generated signals
|
||||
frequency = 10, # Frequency of generated signals
|
||||
stddev = 2, # Standard deviation of random signals (normal distributed)
|
||||
rate = 10.0, # Sample rate
|
||||
offset = 1.0, # Constant offset
|
||||
realtime = true, # Wait between emitting each sample
|
||||
limit = 1000, # Only emit 1000 samples, then stop
|
||||
monitor_missed = true # Count and warn about missed steps
|
||||
# Number of values per sample
|
||||
values = 3,
|
||||
|
||||
# Amplitude of generated signals
|
||||
amplitude = [ 1.2, 0.0, 4.0 ],
|
||||
|
||||
# Frequency of generated signals in Hz
|
||||
frequency = 10,
|
||||
|
||||
# Standard deviation of random signals (normal distributed)
|
||||
stddev = 2,
|
||||
|
||||
# Sample rate in Hz
|
||||
rate = 10.0,
|
||||
|
||||
# Constant offset
|
||||
offset = 1.0,
|
||||
|
||||
# Wait between emitting each sample
|
||||
realtime = true,
|
||||
|
||||
# Only emit 1000 samples, then stop
|
||||
limit = 1000,
|
||||
|
||||
# Count and warn about missed steps
|
||||
monitor_missed = true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,78 +2,94 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
nodes = {
|
||||
udp_node = { # The dictionary is indexed by the name of the node.
|
||||
type = "socket", # For a list of available node-types run: 'villas-node -h'
|
||||
vectorize = 30, # Receive and sent 30 samples per message (combining).
|
||||
samplelen = 10 # The maximum number of samples this node can receive
|
||||
udp_node = {
|
||||
type = "socket",
|
||||
|
||||
builtin = false, # By default, all nodes will have a few builtin hooks attached to them.
|
||||
# When collecting statistics or measurements these are undesired.
|
||||
# Receive and sent 30 samples per message (combining)
|
||||
vectorize = 30,
|
||||
|
||||
### The following settings are specific to the socket node-type!! ###
|
||||
# The maximum number of samples this node can receive
|
||||
samplelen = 10
|
||||
|
||||
layer = "udp", # Layer can be one of:
|
||||
# - udp Send / receive L4 UDP packets
|
||||
# - ip Send / receive L3 IP packets
|
||||
# - eth Send / receive L2 Ethernet frames (IEEE802.3)
|
||||
# By default, all nodes will have a few builtin hooks attached to them
|
||||
# When collecting statistics or measurements these are undesired
|
||||
builtin = false,
|
||||
|
||||
format = "gtnet", # For a list of available node-types run: 'villas-node -h'
|
||||
# Layer can be one of:
|
||||
# - udp Send / receive L4 UDP packets
|
||||
# - ip Send / receive L3 IP packets
|
||||
# - eth Send / receive L2 Ethernet frames (IEEE802.3)
|
||||
layer = "udp",
|
||||
|
||||
|
||||
format = "gtnet",
|
||||
|
||||
in = {
|
||||
address = "127.0.0.1:12001" # This node only received messages on this IP:Port pair
|
||||
# This node only received messages on this IP:Port pair
|
||||
address = "127.0.0.1:12001"
|
||||
|
||||
verify_source = true # Check if source address of incoming packets matches the remote address.
|
||||
# Check if source address of incoming packets matches the remote address
|
||||
verify_source = true
|
||||
},
|
||||
out = {
|
||||
address = "127.0.0.1:12000", # This node sends outgoing messages to this IP:Port pair
|
||||
# This node sends outgoing messages to this IP:Port pair
|
||||
address = "127.0.0.1:12000",
|
||||
}
|
||||
}
|
||||
|
||||
# Raw Ethernet frames
|
||||
ethernet_node = {
|
||||
type = "socket", # See above.
|
||||
type = "socket",
|
||||
|
||||
### The following settings are specific to the socket node-type!! ###
|
||||
|
||||
layer = "eth",
|
||||
layer = "eth",
|
||||
in = {
|
||||
address = "12:34:56:78:90:AB%lo:12002"
|
||||
address = "12:34:56:78:90:AB%lo:12002"
|
||||
},
|
||||
out = {
|
||||
address = "12:34:56:78:90:AB%lo:12002"
|
||||
}
|
||||
},
|
||||
|
||||
# Datagram UNIX domain sockets require two endpoints
|
||||
unix_domain_node = {
|
||||
type = "socket",
|
||||
layer = "unix", # Datagram UNIX domain sockets require two endpoints
|
||||
type = "socket",
|
||||
layer = "unix",
|
||||
|
||||
in = {
|
||||
address = "/var/run/villas-node/node.sock"
|
||||
},
|
||||
out = {
|
||||
address = "/var/run/villas-node/client.sock"
|
||||
address = "/var/run/villas-node/client.sock"
|
||||
}
|
||||
}
|
||||
|
||||
udp_multicast_node = { # The dictionary is indexed by the name of the node.
|
||||
type = "socket", # For a list of available node-types run: 'villas-node -h'
|
||||
|
||||
### The following settings are specific to the socket node-type!! ###
|
||||
udp_multicast_node = {
|
||||
type = "socket",
|
||||
|
||||
in = {
|
||||
address = "127.0.0.1:12001" # This node only received messages on this IP:Port pair
|
||||
# This node only received messages on this IP:Port pair
|
||||
address = "127.0.0.1:12001"
|
||||
|
||||
multicast = { # IGMP multicast is only support for layer = (ip|udp)
|
||||
enabled = true,
|
||||
# IGMP multicast is only support for layer = (ip|udp)
|
||||
multicast = {
|
||||
enabled = true,
|
||||
|
||||
group = "224.1.2.3", # The multicast group. Must be within 224.0.0.0/4
|
||||
interface = "1.2.3.4", # The IP address of the interface which should receive multicast packets.
|
||||
ttl = 128, # The time to live for outgoing multicast packets.
|
||||
loop = false, # Whether or not to loopback outgoing multicast packets to the local host.
|
||||
# The multicast group. Must be within 224.0.0.0/4
|
||||
group = "224.1.2.3",
|
||||
|
||||
# The IP address of the interface which should receive multicast packets
|
||||
interface = "1.2.3.4",
|
||||
|
||||
# The time to live for outgoing multicast packets
|
||||
ttl = 128,
|
||||
|
||||
# Whether or not to loopback outgoing multicast packets to the local host
|
||||
loop = false,
|
||||
}
|
||||
},
|
||||
out = {
|
||||
address = "127.0.0.1:12000", # This node sends outgoing messages to this IP:Port pair
|
||||
# This node sends outgoing messages to this IP:Port pair
|
||||
address = "127.0.0.1:12000",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,44 +2,50 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
nodes = {
|
||||
rtt_node = { # The "test_rtt" node-type runs a set of test cases for varying
|
||||
type = "test_rtt", # sending rates, number of values and generates statistics.
|
||||
cooldown = 2, # The cooldown time between each test case in seconds
|
||||
|
||||
prefix = "test_rtt_%y-%m-%d_%H-%M-%S", # An optional prefix in the filename
|
||||
output = "./results", # The output directory for all results
|
||||
# The results of each test case will be written to a separate file.
|
||||
format = "villas.human", # The output format of the result files.
|
||||
# The "test_rtt" node-type runs a set of test cases for varying
|
||||
# sending rates, number of values and generates statistics
|
||||
# The cooldown time between each test case in seconds
|
||||
rtt_node = {
|
||||
type = "test_rtt",
|
||||
cooldown = 2,
|
||||
|
||||
cases = ( # The list of test cases
|
||||
# Each test case can specify a single or an array of rates and values
|
||||
# If arrays are used, we will generate multiple test cases with all
|
||||
# possible combinations
|
||||
# An optional prefix in the filename
|
||||
prefix = "test_rtt_%y-%m-%d_%H-%M-%S",
|
||||
|
||||
# The output directory for all results
|
||||
# The results of each test case will be written to a separate file
|
||||
output = "./results",
|
||||
|
||||
# The output format of the result files
|
||||
format = "villas.human",
|
||||
|
||||
# The list of test cases
|
||||
# Each test case can specify a single or an array of rates and values
|
||||
# If arrays are used, we will generate multiple test cases with all
|
||||
# possible combinations
|
||||
cases = (
|
||||
{
|
||||
rates = 55.0, # The sending rate in Hz
|
||||
values = [ 5, 10, 20], # The number of values which should be send in each sample
|
||||
limit = 100 # The number of samples which should be send during this test case
|
||||
# The sending rate in Hz
|
||||
rates = 55.0,
|
||||
|
||||
# The number of values which should be send in each sample
|
||||
values = [ 5, 10, 20],
|
||||
|
||||
# The number of samples which should be send during this test case
|
||||
limit = 100
|
||||
},
|
||||
{
|
||||
rates = [ 5, 10, 30 ], # An array of rates in Hz
|
||||
values = [ 2, 10, 20 ],# An array of number of values
|
||||
duration = 5 # The duration of the test case in seconds (depending on the sending rate)
|
||||
# An array of sending rates in Hz
|
||||
rates = [ 5, 10, 30 ],
|
||||
|
||||
# An array of number of values
|
||||
values = [ 2, 10, 20 ],
|
||||
|
||||
# The duration of the test case in seconds (depending on the sending rate)
|
||||
duration = 5
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
paths = (
|
||||
{
|
||||
# Simple loopback path to test the node
|
||||
in = "rtt_node"
|
||||
out = "rtt_node"
|
||||
|
||||
# hooks = (
|
||||
# {
|
||||
# type = "print"
|
||||
# }
|
||||
# )
|
||||
}
|
||||
)
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
nodes = {
|
||||
unix_domain_node = {
|
||||
type = "socket",
|
||||
layer = "unix",
|
||||
format = "protobuf",
|
||||
type = "socket",
|
||||
layer = "unix",
|
||||
format = "protobuf",
|
||||
|
||||
in = {
|
||||
address = "/var/run/villas-node.server.sock"
|
||||
|
|
|
@ -13,16 +13,16 @@ nodes = {
|
|||
# Address to the websocket signaling server
|
||||
server = "https://villas.k8s.eonerc.rwth-aachen.de/ws/signaling"
|
||||
|
||||
# Limit the number of times a channel will retransmit data if not successfully delivered.
|
||||
# This value may be clamped if it exceeds the maximum value supported.
|
||||
# Limit the number of times a channel will retransmit data if not successfully delivered
|
||||
# This value may be clamped if it exceeds the maximum value supported
|
||||
max_retransmits = 0
|
||||
|
||||
# Number of seconds to wait for a WebRTC connection before proceeding the start
|
||||
# of VILLASnode. Mainly used for testing
|
||||
wait_seconds = 10 # in seconds
|
||||
wait_seconds = 10 # In seconds
|
||||
|
||||
# Indicates if data is allowed to be delivered out of order.
|
||||
# The default value of false, does not make guarantees that data will be delivered in order.
|
||||
# Indicates if data is allowed to be delivered out of order
|
||||
# The default value of false, does not make guarantees that data will be delivered in order
|
||||
ordered = false
|
||||
|
||||
# Setting for Interactive Connectivity Establishment
|
||||
|
|
|
@ -5,27 +5,38 @@ nodes = {
|
|||
zeromq_node = {
|
||||
type = "zeromq"
|
||||
|
||||
pattern = "pubsub" # The ZeroMQ pattern. One of pubsub, radiodish
|
||||
ipv6 = false # Enable IPv6 support
|
||||
# The ZeroMQ pattern. One of pubsub, radiodish
|
||||
pattern = "pubsub"
|
||||
|
||||
curve = { # Z85 encoded Curve25519 keys
|
||||
# Enable IPv6 support
|
||||
ipv6 = false
|
||||
|
||||
# Z85 encoded Curve25519 keys
|
||||
curve = {
|
||||
enabled = false,
|
||||
public_key = "Veg+Q.V-c&1k>yVh663gQ^7fL($y47gybE-nZP1L"
|
||||
secret_key = "HPY.+mFuB[jGs@(zZr6$IZ1H1dZ7Ji*j>oi@O?Pc"
|
||||
}
|
||||
|
||||
in = {
|
||||
subscribe = "tcp://*:1234" # The subscribe endpoint.
|
||||
# See http://api.zeromq.org/2-1:zmq-bind for details.
|
||||
filter = "ab184" # A filter which is prefix matched for each received msg
|
||||
# The subscribe endpoint
|
||||
# See http://api.zeromq.org/2-1:zmq-bind for details
|
||||
subscribe = "tcp://*:1234"
|
||||
|
||||
# A filter which is prefix matched for each received msg
|
||||
filter = "ab184"
|
||||
}
|
||||
out = {
|
||||
publish = [ # The publish endpoints.
|
||||
"tcp://localhost:1235", # See http://api.zeromq.org/2-1:zmq-connect for details.
|
||||
# The publish endpoints
|
||||
# See http://api.zeromq.org/2-1:zmq-connect for details
|
||||
publish = [
|
||||
|
||||
"tcp://localhost:1235",
|
||||
"tcp://localhost:12444"
|
||||
]
|
||||
|
||||
filter = "ab184" # A prefix which is pre-pended to each message.
|
||||
# A prefix which is pre-pended to each message
|
||||
filter = "ab184"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,19 +3,29 @@
|
|||
|
||||
paths = (
|
||||
{
|
||||
enabled = true, # Enable this path (default: true)
|
||||
reverse = true, # Setup a path in the reverse direction as well (default: false)
|
||||
# Enable this path (default: true)
|
||||
enabled = true,
|
||||
|
||||
in = "udp_node", # Name of the node we receive messages from (see node dictionary)
|
||||
out = "ethernet_node", # Name of the node we send messages to.
|
||||
# Setup a path in the reverse direction as well (default: false)
|
||||
reverse = true,
|
||||
|
||||
rate = 10.0 # A rate at which this path will be triggered if no input node receives new data
|
||||
# Name of the node we receive messages from (see node dictionary)
|
||||
in = "udp_node",
|
||||
|
||||
# Name of the node we send messages to
|
||||
out = "ethernet_node",
|
||||
|
||||
# A rate at which this path will be triggered if no input node receives new data
|
||||
rate = 10.0
|
||||
|
||||
queuelen = 128,
|
||||
|
||||
mode = "all", # When this path should be triggered
|
||||
# - "all": After all masked input nodes received new data
|
||||
# - "any": After any of the masked input nodes received new data
|
||||
mask = [ "udp_node" ], # A list of input nodes which will trigger the path
|
||||
# When this path should be triggered
|
||||
# - "all": After all masked input nodes received new data
|
||||
# - "any": After any of the masked input nodes received new data
|
||||
mode = "all",
|
||||
|
||||
# A list of input nodes which will trigger the path
|
||||
mask = [ "udp_node" ],
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
#* GTNET-SKT test configuration.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
#* GTNET-SKT test configuration
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
|
@ -18,7 +14,7 @@ nodes = {
|
|||
format = "gtnet"
|
||||
|
||||
in = {
|
||||
address = "*:12000" # Local ip:port, use '*' for random port
|
||||
address = "*:12000"
|
||||
}
|
||||
out = {
|
||||
address = "134.130.169.80:12001"
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
# GTNET-SKT test configuration.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
# GTNET-SKT test configuration
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
|
@ -18,7 +14,7 @@ nodes = {
|
|||
format = "villas.binary"
|
||||
|
||||
in = {
|
||||
address = "192.168.88.128:12002" # Local ip:port, use '*' for random port
|
||||
address = "192.168.88.128:12002"
|
||||
}
|
||||
out = {
|
||||
address = "192.168.88.129:12001"
|
||||
|
@ -26,7 +22,7 @@ nodes = {
|
|||
|
||||
netem = {
|
||||
enabled = false
|
||||
delay = 1000000 # In micro seconds!
|
||||
delay = 1000000
|
||||
jitter = 300000
|
||||
distribution = "normal"
|
||||
}
|
||||
|
@ -37,7 +33,7 @@ nodes = {
|
|||
format = "villas.binary"
|
||||
|
||||
in = {
|
||||
address = "*:12004" # Local ip:port, use '*' for random port
|
||||
address = "*:12004"
|
||||
}
|
||||
out = {
|
||||
address = "192.168.88.129:12005"
|
||||
|
@ -47,8 +43,8 @@ nodes = {
|
|||
|
||||
paths = (
|
||||
{
|
||||
in = "node1" # Name of the node we listen to (see above)
|
||||
out = "node1" # And we loop back to the origin
|
||||
in = "node1"
|
||||
out = "node1"
|
||||
|
||||
hooks = (
|
||||
{
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
# GTNET-SKT test configuration.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
# GTNET-SKT test configuration
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
|
@ -18,7 +14,7 @@ nodes = {
|
|||
format = "villas.binary"
|
||||
|
||||
in = {
|
||||
address = "192.168.88.128:12002" # Local ip:port, use '*' for random port
|
||||
address = "192.168.88.128:12002"
|
||||
}
|
||||
out = {
|
||||
address = "192.168.88.129:12001"
|
||||
|
@ -26,7 +22,7 @@ nodes = {
|
|||
|
||||
netem = {
|
||||
enabled = false
|
||||
delay = 1000000 # In micro seconds!
|
||||
delay = 1000000
|
||||
jitter = 300000
|
||||
distribution = "normal"
|
||||
}
|
||||
|
@ -37,7 +33,7 @@ nodes = {
|
|||
format = "villas.binary"
|
||||
|
||||
in = {
|
||||
address = "192.168.88.128:12004" # Local ip:port, use '*' for random port
|
||||
address = "192.168.88.128:12004"
|
||||
}
|
||||
out = {
|
||||
address = "192.168.88.129:12001"
|
||||
|
@ -47,8 +43,8 @@ nodes = {
|
|||
|
||||
paths = (
|
||||
{
|
||||
in = "node1" # Name of the node we listen to (see above)
|
||||
out = "node2" # And we loop back to the origin
|
||||
in = "node1"
|
||||
out = "node2"
|
||||
|
||||
hooks = (
|
||||
{
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
# GTNET-SKT test configuration.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
# GTNET-SKT test configuration
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
|
@ -19,7 +15,7 @@ nodes = {
|
|||
format = "gtnet"
|
||||
|
||||
in = {
|
||||
address = "192.168.88.128:12002" # Local ip:port, use '*' for random port
|
||||
address = "192.168.88.128:12002"
|
||||
}
|
||||
out = {
|
||||
address = "192.168.88.129:12001"
|
||||
|
@ -27,7 +23,7 @@ nodes = {
|
|||
|
||||
netem = {
|
||||
enabled = false
|
||||
delay = 1000000 # In micro seconds!
|
||||
delay = 1000000
|
||||
jitter = 300000
|
||||
distribution = "normal"
|
||||
}
|
||||
|
@ -38,7 +34,7 @@ nodes = {
|
|||
format = "gtnet"
|
||||
|
||||
in = {
|
||||
address = "192.168.88.128:12004" # Local ip:port, use '*' for random port
|
||||
address = "192.168.88.128:12004"
|
||||
}
|
||||
out = {
|
||||
address = "192.168.88.129:12001"
|
||||
|
@ -48,8 +44,8 @@ nodes = {
|
|||
|
||||
paths = (
|
||||
{
|
||||
in = "node1" # Name of the node we listen to (see above)
|
||||
out = "node2" # And we loop back to the origin
|
||||
in = "node1"
|
||||
out = "node2"
|
||||
|
||||
hooks = (
|
||||
{
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
# GTNET-SKT test configuration.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
# GTNET-SKT test configuration
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
|
@ -19,7 +15,7 @@ nodes = {
|
|||
format = "gtnet"
|
||||
|
||||
in = {
|
||||
address = "134.130.169.31:12002" # Local ip:port, use '*' for random port
|
||||
address = "134.130.169.31:12002"
|
||||
}
|
||||
out = {
|
||||
address = "134.130.169.98:12001"
|
||||
|
@ -27,7 +23,7 @@ nodes = {
|
|||
|
||||
netem = {
|
||||
enabled = false
|
||||
delay = 1000000 # In micro seconds!
|
||||
delay = 1000000
|
||||
jitter = 300000
|
||||
distribution = "normal"
|
||||
}
|
||||
|
@ -38,7 +34,7 @@ nodes = {
|
|||
format = "gtnet"
|
||||
|
||||
in = {
|
||||
address = "192.168.88.128:12004" # Local ip:port, use '*' for random port
|
||||
address = "192.168.88.128:12004"
|
||||
}
|
||||
out = {
|
||||
address = "192.168.88.129:12001"
|
||||
|
@ -48,8 +44,8 @@ nodes = {
|
|||
|
||||
paths = (
|
||||
{
|
||||
in = "node1", # Name of the node we listen to (see above)
|
||||
out = "node1", # And we loop back to the origin
|
||||
in = "node1",
|
||||
out = "node1",
|
||||
|
||||
hooks = (
|
||||
{
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
# GTNET-SKT test configuration.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
# GTNET-SKT test configuration
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
|
@ -22,7 +18,8 @@ nodes = {
|
|||
}
|
||||
|
||||
in = {
|
||||
address = "134.130.169.31:12002" # Local ip:port, use '*' for random port
|
||||
# Local ip:port, use '*' for random port
|
||||
address = "134.130.169.31:12002"
|
||||
}
|
||||
out = {
|
||||
address = "134.130.169.98:12001"
|
||||
|
@ -30,7 +27,7 @@ nodes = {
|
|||
|
||||
netem = {
|
||||
enabled = false
|
||||
delay = 1000000 # In micro seconds!
|
||||
delay = 1000000 # In micro seconds!
|
||||
jitter = 300000
|
||||
distribution = "normal"
|
||||
}
|
||||
|
@ -41,7 +38,8 @@ nodes = {
|
|||
format = "gtnet"
|
||||
|
||||
in = {
|
||||
address = "192.168.88.128:12004" # Local ip:port, use '*' for random port
|
||||
# Local ip:port, use '*' for random port
|
||||
address = "192.168.88.128:12004"
|
||||
}
|
||||
out = {
|
||||
address = "192.168.88.129:12001"
|
||||
|
@ -51,8 +49,11 @@ nodes = {
|
|||
|
||||
paths = (
|
||||
{
|
||||
in = "node1" # Name of the node we listen to (see above)
|
||||
out = "node1" # And we loop back to the origin
|
||||
# Name of the node we listen to (see above)
|
||||
in = "node1"
|
||||
|
||||
# And we loop back to the origin
|
||||
out = "node1"
|
||||
|
||||
hooks = (
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# This is an example for a minimal loopback configuration.
|
||||
# This is an example for a minimal loopback configuration
|
||||
#
|
||||
# All messages will be sent back to the origin using UDP packets.
|
||||
#
|
||||
|
@ -38,7 +38,7 @@ nodes = {
|
|||
}
|
||||
|
||||
in = {
|
||||
address = "134.130.169.31:12002" # Local ip:port, use '*' for random port
|
||||
address = "134.130.169.31:12002"
|
||||
}
|
||||
out = {
|
||||
address = "134.130.169.98:12001"
|
||||
|
@ -46,7 +46,7 @@ nodes = {
|
|||
|
||||
netem = {
|
||||
enabled = false
|
||||
delay = 1000000 # In micro seconds!
|
||||
delay = 1000000
|
||||
jitter = 300000
|
||||
distribution = "normal"
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ nodes = {
|
|||
}
|
||||
|
||||
in = {
|
||||
address = "134.130.169.31:12004", # Local ip:port, use '*' for random port
|
||||
address = "134.130.169.31:12004",
|
||||
}
|
||||
out = {
|
||||
address = "134.130.169.99:12003",
|
||||
|
@ -69,8 +69,8 @@ nodes = {
|
|||
|
||||
paths = (
|
||||
{
|
||||
in = "node1" # Name of the node we listen to (see above)
|
||||
out = "node1" # And we loop back to the origin
|
||||
in = "node1"
|
||||
out = "node1"
|
||||
hooks = (
|
||||
{
|
||||
type = "print"
|
||||
|
|
|
@ -8,10 +8,10 @@ nodes = {
|
|||
rpi-1 = {
|
||||
type = "socket"
|
||||
layer = "udp"
|
||||
format = "gtnet" # pre-built format to communicate in RTDS GTNET-SKT payload
|
||||
format = "gtnet" # Pre-built format to communicate in RTDS GTNET-SKT payload
|
||||
|
||||
in = {
|
||||
address = "*:12005" # villas node machine IP and port number
|
||||
address = "*:12005" # VILLASnode machine IP and port number
|
||||
|
||||
signals = {
|
||||
count = 8
|
||||
|
@ -26,16 +26,16 @@ nodes = {
|
|||
)
|
||||
},
|
||||
out = {
|
||||
address = "192.168.0.5:12005" # remote machine IP and port number
|
||||
address = "192.168.0.5:12005" # Remote machine IP and port number
|
||||
}
|
||||
},
|
||||
rpi-2 = {
|
||||
type = "socket"
|
||||
layer = "udp"
|
||||
format = "gtnet" # pre-built format to communicate in RTDS GTNET-SKT payload
|
||||
format = "gtnet" # Pre-built format to communicate in RTDS GTNET-SKT payload
|
||||
|
||||
in = {
|
||||
address = "*:12006" # villas node machine IP and port number
|
||||
address = "*:12006" # VILLASnode machine IP and port number
|
||||
|
||||
signals = {
|
||||
count = 8
|
||||
|
@ -50,7 +50,7 @@ nodes = {
|
|||
)
|
||||
}
|
||||
out = {
|
||||
address = "192.168.0.6:12006" # remote machine IP and port number
|
||||
address = "192.168.0.6:12006" # Remote machine IP and port number
|
||||
}
|
||||
},
|
||||
rtds-1 = {
|
||||
|
@ -59,7 +59,7 @@ nodes = {
|
|||
format = "gtnet"
|
||||
|
||||
in = {
|
||||
address = "*:12083" # villas node machine IP and port number
|
||||
address = "*:12083" # VILLASnode machine IP and port number
|
||||
|
||||
signals = {
|
||||
count = 8
|
||||
|
@ -74,7 +74,7 @@ nodes = {
|
|||
)
|
||||
}
|
||||
out = {
|
||||
address = "192.168.0.4:12083" # remote machine IP and port number
|
||||
address = "192.168.0.4:12083" # Remote machine IP and port number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ paths = (
|
|||
# and set reverse = true
|
||||
# Example:
|
||||
# {
|
||||
# in = [ "rpi-1" ],
|
||||
# out = [ "rtds-1" ],
|
||||
# reverse = true
|
||||
# in = [ "rpi-1" ],
|
||||
# out = [ "rtds-1" ],
|
||||
# reverse = true
|
||||
# }
|
||||
)
|
||||
|
|
|
@ -71,7 +71,7 @@ paths = (
|
|||
reverse = false,
|
||||
|
||||
# The mode of a path determines when the path is triggered
|
||||
# and forwarding samples to its destination nodes.
|
||||
# and forwarding samples to its destination nodes
|
||||
mode = "any",
|
||||
|
||||
# List of nodes which trigger the path
|
||||
|
|
|
@ -14,31 +14,31 @@ nodes = {
|
|||
address = "134.130.169.31:12000"
|
||||
|
||||
signals = (
|
||||
{ name="trigger", type="integer" },
|
||||
{ name="if1_tx_phA_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp3_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp3_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp3_phase", type="float" }
|
||||
{ name="trigger", type="integer" },
|
||||
{ name="if1_tx_phA_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp3_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp3_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp3_phase", type="float" }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -60,33 +60,32 @@ nodes = {
|
|||
address = "134.130.169.31:12001"
|
||||
|
||||
signals = (
|
||||
{ name="trigger", type="integer" },
|
||||
{ name="if1_tx_phA_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp3_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp3_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp3_phase", type="float" }
|
||||
{ name="trigger", type="integer" },
|
||||
{ name="if1_tx_phA_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phA_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phA_dp3_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phB_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phB_dp3_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp0_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp0_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp1_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp1_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp2_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp2_phase", type="float" },
|
||||
{ name="if1_tx_phC_dp3_mag", type="float" },
|
||||
{ name="if1_tx_phC_dp3_phase", type="float" }
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
out = {
|
||||
|
@ -107,15 +106,15 @@ nodes = {
|
|||
address = "134.130.169.31:12002"
|
||||
|
||||
signals = (
|
||||
{ name="orgn_V3phRMSintrf", type="float", unit="V" },
|
||||
{ name="orgn_Pintrf", type="float", unit="W" },
|
||||
{ name="orgn_Qintrf", type="float", unit="Var" },
|
||||
{ name="orgn_Sintrf", type="float", unit="VA" },
|
||||
{ name="if1_V3phRMS", type="float", unit="V" },
|
||||
{ name="if1_I3phRMS", type="float", unit="A" },
|
||||
{ name="if1_P", type="float", unit="W" },
|
||||
{ name="if1_Q", type="float", unit="Var" },
|
||||
{ name="if1_S", type="float", unit="VA" }
|
||||
{ name="orgn_V3phRMSintrf", type="float", unit="V" },
|
||||
{ name="orgn_Pintrf", type="float", unit="W" },
|
||||
{ name="orgn_Qintrf", type="float", unit="Var" },
|
||||
{ name="orgn_Sintrf", type="float", unit="VA" },
|
||||
{ name="if1_V3phRMS", type="float", unit="V" },
|
||||
{ name="if1_I3phRMS", type="float", unit="A" },
|
||||
{ name="if1_P", type="float", unit="W" },
|
||||
{ name="if1_Q", type="float", unit="Var" },
|
||||
{ name="if1_S", type="float", unit="VA" }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@ nodes = {
|
|||
|
||||
netem = {
|
||||
enabled = true,
|
||||
loss = 0, # in %
|
||||
corrupt = 0, # in %
|
||||
duplicate = 0, # in %
|
||||
delay = 100000, # in uS
|
||||
jitter = 5000, # in uS
|
||||
loss = 0, # In %
|
||||
corrupt = 0, # In %
|
||||
duplicate = 0, # In %
|
||||
delay = 100000, # In uS
|
||||
jitter = 5000, # In uS
|
||||
distribution = "normal"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# This is an example for a minimal loopback configuration.
|
||||
# This is an example for a minimal loopback configuration
|
||||
#
|
||||
# All messages will be sent back to the origin using UDP packets.
|
||||
#
|
||||
|
@ -21,10 +21,6 @@
|
|||
#
|
||||
# $ villas pipe etc/loopback.conf node2
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
@ -35,14 +31,15 @@ nodes = {
|
|||
layer = "udp"
|
||||
|
||||
in = {
|
||||
address = "127.0.0.1:12000" # Local ip:port, use '*' for random port
|
||||
# Local ip:port, use '*' for random port
|
||||
address = "127.0.0.1:12000"
|
||||
}
|
||||
out = {
|
||||
address = "127.0.0.1:12001"
|
||||
|
||||
netem = {
|
||||
enabled = false
|
||||
delay = 1000000 # In micro seconds!
|
||||
delay = 1000000 # In micro seconds!
|
||||
jitter = 300000
|
||||
distribution = "normal"
|
||||
}
|
||||
|
@ -52,7 +49,8 @@ nodes = {
|
|||
type = "socket"
|
||||
layer = "udp"
|
||||
in = {
|
||||
address = "127.0.0.1:12001" # Local ip:port, use '*' for random port
|
||||
# Local ip:port, use '*' for random port
|
||||
address = "127.0.0.1:12001"
|
||||
}
|
||||
out = {
|
||||
address = "127.0.0.1:12002"
|
||||
|
@ -62,7 +60,8 @@ nodes = {
|
|||
type = "socket"
|
||||
layer = "udp"
|
||||
in = {
|
||||
address = "127.0.0.1:12002" # Local ip:port, use '*' for random port
|
||||
# Local ip:port, use '*' for random port
|
||||
address = "127.0.0.1:12002"
|
||||
}
|
||||
out = {
|
||||
address = "127.0.0.1:12000"
|
||||
|
@ -72,7 +71,8 @@ nodes = {
|
|||
type = "socket"
|
||||
layer = "udp"
|
||||
in = {
|
||||
address = "127.0.0.1:12003" # Local ip:port, use '*' for random port
|
||||
# Local ip:port, use '*' for random port
|
||||
address = "127.0.0.1:12003"
|
||||
}
|
||||
out = {
|
||||
address = "127.0.0.1:12003"
|
||||
|
@ -82,8 +82,11 @@ nodes = {
|
|||
|
||||
paths = (
|
||||
{
|
||||
in = "node1" # Name of the node we listen to (see above)
|
||||
out = "node2" # And we loop back to the origin
|
||||
# Name of the node we listen to (see above)
|
||||
in = "node1"
|
||||
|
||||
# And we loop back to the origin
|
||||
out = "node2"
|
||||
|
||||
hooks = (
|
||||
{
|
||||
|
|
|
@ -12,7 +12,8 @@ nodes = {
|
|||
enabled = false,
|
||||
type = "shmem",
|
||||
in = {
|
||||
name = "/dpsim-villas", # Name of shared memory segment for sending side
|
||||
# Name of shared memory segment for sending side
|
||||
name = "/dpsim-villas",
|
||||
hooks = (
|
||||
{ type = "stats" }
|
||||
),
|
||||
|
@ -24,15 +25,19 @@ nodes = {
|
|||
}
|
||||
},
|
||||
out = {
|
||||
name = "/villas-dpsim" # Name of shared memory segment for receiving side
|
||||
# Name of shared memory segment for receiving side
|
||||
name = "/villas-dpsim"
|
||||
signals = {
|
||||
count = 1,
|
||||
type = "complex"
|
||||
}
|
||||
|
||||
},
|
||||
queuelen = 1024, # Length of the queues
|
||||
polling = true, # We can busy-wait or use pthread condition variables for synchronizations
|
||||
# Length of the queues
|
||||
queuelen = 1024,
|
||||
|
||||
# We can busy-wait or use pthread condition variables for synchronizations
|
||||
polling = true,
|
||||
},
|
||||
|
||||
broker = {
|
||||
|
@ -64,16 +69,14 @@ paths = (
|
|||
in = "sig",
|
||||
out = "broker",
|
||||
|
||||
# mode: any/all
|
||||
# Condition of which/how many source nodes have to receive
|
||||
# at least one sample for the path to be triggered
|
||||
mode = "any",
|
||||
# reverse = true
|
||||
# reverse = true
|
||||
}
|
||||
# ,{
|
||||
# in = "nano";
|
||||
# out = "dpsim";
|
||||
# mode = "any"
|
||||
# in = "nano";
|
||||
# out = "dpsim";
|
||||
# mode = "any"
|
||||
# }
|
||||
|
||||
)
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
# Example configuration file for VILLASnode.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
# Example configuration file for VILLASnode websocket node-type
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
# Example configuration file for VILLASnode.
|
||||
#
|
||||
# The syntax of this file is similar to JSON.
|
||||
# A detailed description of the format can be found here:
|
||||
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
# Example configuration file for VILLASnode websocket node-type
|
||||
#
|
||||
# Author: Steffen Vogel <post@steffenvogel.de>
|
||||
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
||||
|
|
82
flake.lock
generated
82
flake.lock
generated
|
@ -1,97 +1,23 @@
|
|||
{
|
||||
"nodes": {
|
||||
"ethercat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1694079333,
|
||||
"narHash": "sha256-6F3zBhnU4CFpiO+Cnbd6ecUuiGH/KUntpPfuSYZ+rAI=",
|
||||
"owner": "etherlab.org",
|
||||
"repo": "ethercat",
|
||||
"rev": "722b2d607c4fc004ebf5204aaede0059c02274f4",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"owner": "etherlab.org",
|
||||
"ref": "stable-1.5",
|
||||
"repo": "ethercat",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"lib60870": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1672404819,
|
||||
"narHash": "sha256-9o+gWQbpCJb+UZzPNmzGqpWD0QbGjg41is/f1POUEQs=",
|
||||
"owner": "mz-automation",
|
||||
"repo": "lib60870",
|
||||
"rev": "53a6b3c1cf3023e51cf81763b1ccf048edcd1c64",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "mz-automation",
|
||||
"ref": "v2.3.2",
|
||||
"repo": "lib60870",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"libdatachannel": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1683797946,
|
||||
"narHash": "sha256-kSK+5gFMG6tq89R1m08gNBKPdwyR/mLEDhWXQ/uk34o=",
|
||||
"ref": "refs/tags/v0.18.4",
|
||||
"rev": "7a5e01071ae635e06f175233abd11d623f09cbb8",
|
||||
"revCount": 2459,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/paullouisageneau/libdatachannel.git"
|
||||
},
|
||||
"original": {
|
||||
"ref": "refs/tags/v0.18.4",
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/paullouisageneau/libdatachannel.git"
|
||||
}
|
||||
},
|
||||
"libiec61850": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1647022552,
|
||||
"narHash": "sha256-1vT0ry6IJqilpM7g9l7fx+ET+Dyo24WAyWqTyPM9nQw=",
|
||||
"owner": "mz-automation",
|
||||
"repo": "libiec61850",
|
||||
"rev": "210cf30897631fe2006ac50483caf8fd616622a2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "mz-automation",
|
||||
"ref": "v1.5.1",
|
||||
"repo": "libiec61850",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1705957679,
|
||||
"narHash": "sha256-Q8LJaVZGJ9wo33wBafvZSzapYsjOaNjP/pOnSiKVGHY=",
|
||||
"lastModified": 1712666087,
|
||||
"narHash": "sha256-WwjUkWsjlU8iUImbivlYxNyMB1L5YVqE8QotQdL9jWc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9a333eaa80901efe01df07eade2c16d183761fa3",
|
||||
"rev": "a76c4553d7e741e17f289224eda135423de0491d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-23.05",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"ethercat": "ethercat",
|
||||
"lib60870": "lib60870",
|
||||
"libdatachannel": "libdatachannel",
|
||||
"libiec61850": "libiec61850",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
|
|
325
flake.nix
325
flake.nix
|
@ -4,209 +4,156 @@
|
|||
description = "VILLASnode is a client/server application to connect simulation equipment and software.";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/release-23.05";
|
||||
|
||||
ethercat = {
|
||||
url = "gitlab:etherlab.org/ethercat/stable-1.5";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
lib60870 = {
|
||||
url = "github:mz-automation/lib60870/v2.3.2";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
libdatachannel = {
|
||||
type = "git";
|
||||
url = "https://github.com/paullouisageneau/libdatachannel.git";
|
||||
ref = "refs/tags/v0.18.4";
|
||||
submodules = true;
|
||||
flake = false;
|
||||
};
|
||||
|
||||
libiec61850 = {
|
||||
url = "github:mz-automation/libiec61850/v1.5.1";
|
||||
flake = false;
|
||||
};
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
...
|
||||
} @ inputs: let
|
||||
inherit (nixpkgs) lib;
|
||||
outputs =
|
||||
{ self, nixpkgs, ... }:
|
||||
let
|
||||
inherit (nixpkgs) lib;
|
||||
|
||||
nixDir = ./packaging/nix;
|
||||
nixDir = ./packaging/nix;
|
||||
|
||||
# Add separateDebugInfo to a derivation
|
||||
addSeparateDebugInfo = d:
|
||||
d.overrideAttrs {
|
||||
separateDebugInfo = true;
|
||||
};
|
||||
# Add separateDebugInfo to a derivation
|
||||
addSeparateDebugInfo = d: d.overrideAttrs { separateDebugInfo = true; };
|
||||
|
||||
# Supported systems for native compilation
|
||||
supportedSystems = ["x86_64-linux" "aarch64-linux"];
|
||||
# Supported systems for native compilation
|
||||
supportedSystems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
|
||||
# Supported systems to cross compile to
|
||||
supportedCrossSystems = ["aarch64-multiplatform"];
|
||||
# Generate attributes corresponding to all the supported systems
|
||||
forSupportedSystems = lib.genAttrs supportedSystems;
|
||||
|
||||
# Generate attributes corresponding to all the supported systems
|
||||
forSupportedSystems = lib.genAttrs supportedSystems;
|
||||
|
||||
# Generate attributes corresponding to all supported combinations of system and crossSystem
|
||||
forSupportedCrossSystems = f: forSupportedSystems (system: lib.genAttrs supportedCrossSystems (f system));
|
||||
|
||||
# Initialize nixpkgs for the specified `system`
|
||||
pkgsFor = system:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = with self.overlays; [default];
|
||||
};
|
||||
|
||||
# Initialize nixpkgs for cross-compiling from `system` to `crossSystem`
|
||||
crossPkgsFor = system: crossSystem:
|
||||
(import nixpkgs {
|
||||
inherit system;
|
||||
overlays = with self.overlays; [
|
||||
default
|
||||
minimal
|
||||
];
|
||||
})
|
||||
.pkgsCross
|
||||
.${crossSystem};
|
||||
|
||||
# Initialize development nixpkgs for the specified `system`
|
||||
devPkgsFor = system:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = with self.overlays; [default debug];
|
||||
};
|
||||
|
||||
# Build villas and its dependencies for the specified `pkgs`
|
||||
packagesWith = pkgs: rec {
|
||||
default = villas;
|
||||
|
||||
villas-python = pkgs.callPackage (nixDir + "/python.nix") {
|
||||
src = ./python;
|
||||
};
|
||||
|
||||
villas-minimal = pkgs.callPackage (nixDir + "/villas.nix") {
|
||||
src = ./.;
|
||||
version = "minimal";
|
||||
};
|
||||
|
||||
villas = villas-minimal.override {
|
||||
version = "full";
|
||||
withAllExtras = true;
|
||||
withAllFormats = true;
|
||||
withAllHooks = true;
|
||||
withAllNodes = true;
|
||||
};
|
||||
|
||||
ethercat = pkgs.callPackage (nixDir + "/ethercat.nix") {
|
||||
src = inputs.ethercat;
|
||||
};
|
||||
|
||||
lib60870 = pkgs.callPackage (nixDir + "/lib60870.nix") {
|
||||
src = inputs.lib60870;
|
||||
};
|
||||
|
||||
libdatachannel = pkgs.callPackage (nixDir + "/libdatachannel.nix") {
|
||||
src = inputs.libdatachannel;
|
||||
};
|
||||
|
||||
libiec61850 = pkgs.callPackage (nixDir + "/libiec61850.nix") {
|
||||
src = inputs.libiec61850;
|
||||
};
|
||||
};
|
||||
in {
|
||||
# Standard flake attribute for normal packages (not cross-compiled)
|
||||
packages = forSupportedSystems (
|
||||
system:
|
||||
packagesWith (pkgsFor system)
|
||||
);
|
||||
|
||||
# Non-standard attribute for cross-compilated packages
|
||||
crossPackages = forSupportedCrossSystems (
|
||||
system: crossSystem:
|
||||
packagesWith (crossPkgsFor system crossSystem)
|
||||
);
|
||||
|
||||
# Standard flake attribute allowing you to add the villas packages to your nixpkgs
|
||||
overlays = {
|
||||
default = final: prev: packagesWith final;
|
||||
debug = final: prev: {
|
||||
jansson = addSeparateDebugInfo prev.jansson;
|
||||
libmodbus = addSeparateDebugInfo prev.libmodbus;
|
||||
};
|
||||
minimal = final: prev: {
|
||||
mosquitto = prev.mosquitto.override {systemd = final.systemdMinimal;};
|
||||
rdma-core = prev.rdma-core.override {udev = final.systemdMinimal;};
|
||||
};
|
||||
};
|
||||
|
||||
# Standard flake attribute for defining developer environments
|
||||
devShells = forSupportedSystems (
|
||||
system: let
|
||||
pkgs = devPkgsFor system;
|
||||
shellHook = ''[ -z "$PS1" ] || exec "$SHELL"'';
|
||||
hardeningDisable = ["all"];
|
||||
packages = with pkgs; [
|
||||
bashInteractive
|
||||
bc
|
||||
boxfort
|
||||
clang-tools
|
||||
criterion
|
||||
jq
|
||||
libffi
|
||||
libgit2
|
||||
pcre
|
||||
reuse
|
||||
cppcheck
|
||||
];
|
||||
in rec {
|
||||
default = full;
|
||||
|
||||
minimal = pkgs.mkShell {
|
||||
inherit shellHook hardeningDisable packages;
|
||||
name = "minimal";
|
||||
inputsFrom = with pkgs; [villas-minimal];
|
||||
# Initialize nixpkgs for the specified `system`
|
||||
pkgsFor =
|
||||
system:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = with self.overlays; [ default ];
|
||||
};
|
||||
|
||||
full = pkgs.mkShell {
|
||||
inherit shellHook hardeningDisable packages;
|
||||
name = "full";
|
||||
inputsFrom = with pkgs; [villas];
|
||||
# Initialize development nixpkgs for the specified `system`
|
||||
devPkgsFor =
|
||||
system:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = with self.overlays; [
|
||||
default
|
||||
debug
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
# Standard flake attribute to add additional checks to `nix flake check`
|
||||
checks = forSupportedSystems (
|
||||
system: let
|
||||
pkgs = pkgsFor system;
|
||||
in {
|
||||
fmt = pkgs.runCommand "check-fmt" {} ''
|
||||
cd ${self}
|
||||
"${pkgs.alejandra}/bin/alejandra" --check . 2>> $out
|
||||
'';
|
||||
}
|
||||
);
|
||||
# Build villas and its dependencies for the specified `pkgs`
|
||||
packagesWith = pkgs: rec {
|
||||
default = villas-node;
|
||||
|
||||
# Standard flake attribute specifying the formatter invoked on `nix fmt`
|
||||
formatter = forSupportedSystems (system: (pkgsFor system).alejandra);
|
||||
villas-node-python = pkgs.callPackage (nixDir + "/python.nix") { src = ./.; };
|
||||
|
||||
# Standard flake attribute for NixOS modules
|
||||
nixosModules = rec {
|
||||
default = villas;
|
||||
villas-node-minimal = pkgs.callPackage (nixDir + "/villas.nix") {
|
||||
src = ./.;
|
||||
version = "minimal";
|
||||
};
|
||||
|
||||
villas = {
|
||||
imports = [(nixDir + "/module.nix")];
|
||||
nixpkgs.overlays = [
|
||||
self.overlays.default
|
||||
];
|
||||
villas-node = villas-node-minimal.override {
|
||||
version = "full";
|
||||
withAllExtras = true;
|
||||
withAllFormats = true;
|
||||
withAllHooks = true;
|
||||
withAllNodes = true;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
# Standard flake attribute for normal packages (not cross-compiled)
|
||||
packages = forSupportedSystems (system: packagesWith (pkgsFor system));
|
||||
|
||||
# Standard flake attribute allowing you to add the villas packages to your nixpkgs
|
||||
overlays = {
|
||||
default = final: prev: packagesWith final;
|
||||
debug = final: prev: {
|
||||
jansson = addSeparateDebugInfo prev.jansson;
|
||||
libmodbus = addSeparateDebugInfo prev.libmodbus;
|
||||
};
|
||||
minimal = final: prev: {
|
||||
mosquitto = prev.mosquitto.override { systemd = final.systemdMinimal; };
|
||||
rdma-core = prev.rdma-core.override { udev = final.systemdMinimal; };
|
||||
};
|
||||
};
|
||||
|
||||
# Standard flake attribute for defining developer environments
|
||||
devShells = forSupportedSystems (
|
||||
system:
|
||||
let
|
||||
pkgs = devPkgsFor system;
|
||||
shellHook = ''[ -z "$PS1" ] || exec "$SHELL"'';
|
||||
hardeningDisable = [ "all" ];
|
||||
packages = with pkgs; [
|
||||
bashInteractive
|
||||
bc
|
||||
boxfort
|
||||
clang-tools
|
||||
criterion
|
||||
jq
|
||||
libffi
|
||||
libgit2
|
||||
pcre
|
||||
reuse
|
||||
cppcheck
|
||||
];
|
||||
in
|
||||
rec {
|
||||
default = full;
|
||||
|
||||
full = pkgs.mkShell {
|
||||
inherit shellHook hardeningDisable packages;
|
||||
name = "full";
|
||||
inputsFrom = with pkgs; [ villas-node ];
|
||||
};
|
||||
|
||||
python = pkgs.mkShell {
|
||||
inherit shellHook hardeningDisable;
|
||||
name = "python";
|
||||
inputsFrom = with pkgs; [ villas-node-python ];
|
||||
packages =
|
||||
with pkgs;
|
||||
packages
|
||||
++ [
|
||||
(python3.withPackages (python-pkgs: [
|
||||
python-pkgs.build
|
||||
python-pkgs.twine
|
||||
]))
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
# Standard flake attribute to add additional checks to `nix flake check`
|
||||
checks = forSupportedSystems (
|
||||
system:
|
||||
let
|
||||
pkgs = pkgsFor system;
|
||||
in
|
||||
{
|
||||
fmt = pkgs.runCommand "check-fmt" { } ''
|
||||
cd ${self}
|
||||
"${pkgs.nixfmt}/bin/nixfmt" --check . 2>> $out
|
||||
'';
|
||||
}
|
||||
);
|
||||
|
||||
# Standard flake attribute specifying the formatter invoked on `nix fmt`
|
||||
formatter = forSupportedSystems (system: (pkgsFor system).alejandra);
|
||||
|
||||
# Standard flake attribute for NixOS modules
|
||||
nixosModules = rec {
|
||||
default = villas;
|
||||
|
||||
villas = {
|
||||
imports = [ (nixDir + "/module.nix") ];
|
||||
nixpkgs.overlays = [ self.overlays.default ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ class I2cFactory : NodeFactory {
|
|||
public:
|
||||
virtual std::string getName() const { return "i2c"; }
|
||||
|
||||
virtual std::string getDescription() const { return "Xilinx's AXI4 iic IP"; }
|
||||
virtual std::string getDescription() const { return "Xilinx's AXI4 IIC IP"; }
|
||||
|
||||
private:
|
||||
virtual Vlnv getCompatibleVlnv() const {
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
|
||||
#include <villas/fpga/dma.h>
|
||||
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <villas/exceptions.hpp>
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <csignal>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
@ -15,7 +14,6 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <CLI11.hpp>
|
||||
#include <rang.hpp>
|
||||
|
||||
#include <villas/exceptions.hpp>
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <jansson.h>
|
||||
#include <string>
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <jansson.h>
|
||||
#include <string>
|
||||
|
|
12916
fpga/thirdparty/CLI11/CLI11.hpp
vendored
12916
fpga/thirdparty/CLI11/CLI11.hpp
vendored
File diff suppressed because it is too large
Load diff
|
@ -160,14 +160,14 @@ public:
|
|||
|
||||
virtual void setRate(double rate, double maxRate = -1) = 0;
|
||||
|
||||
virtual void parse() {
|
||||
virtual void parse(json_t *json) {
|
||||
assert(state == State::INITIALIZED);
|
||||
|
||||
state = State::PARSED;
|
||||
}
|
||||
|
||||
void init() {
|
||||
parse();
|
||||
parse(nullptr);
|
||||
check();
|
||||
prepare();
|
||||
start();
|
||||
|
|
|
@ -59,3 +59,6 @@
|
|||
#cmakedefine REDISPP_WITH_TLS
|
||||
#cmakedefine REDISPP_WITH_URI
|
||||
#cmakedefine RABBITMQ_C_NEW_INCLUDE_DIR
|
||||
|
||||
/* Library versions */
|
||||
#define RTC_VERSION ((@LibDataChannel_VERSION_MAJOR@ << 16) | (@LibDataChannel_VERSION_MINOR@ << 8) | (@LibDataChannel_VERSION_PATCH@ << 0))
|
||||
|
|
|
@ -51,34 +51,25 @@ public:
|
|||
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
// Validate node configuration
|
||||
virtual int check();
|
||||
|
||||
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();
|
||||
};
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
virtual std::string getName() const { return "loopback.internal"; }
|
||||
|
||||
virtual std::string getDescription() const {
|
||||
return "internal loopback node";
|
||||
return "Internal loopback node";
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -21,8 +21,11 @@
|
|||
#include <villas/queue_signalled.h>
|
||||
|
||||
extern "C" {
|
||||
#include <re/re_rtp.h>
|
||||
// clang-format off
|
||||
#include <re/re_types.h>
|
||||
#include <re/re_sa.h>
|
||||
#include <re/re_rtp.h>
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
namespace villas {
|
||||
|
|
|
@ -9,63 +9,78 @@
|
|||
|
||||
#include <villas/format.hpp>
|
||||
#include <villas/list.hpp>
|
||||
#include <villas/node.hpp>
|
||||
#include <villas/task.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
||||
// Forward declarations
|
||||
class NodeCompat;
|
||||
struct Sample;
|
||||
|
||||
struct test_rtt;
|
||||
class TestRTT : public Node {
|
||||
|
||||
struct test_rtt_case {
|
||||
double rate;
|
||||
unsigned values;
|
||||
unsigned limit; // The number of samples we take per test.
|
||||
protected:
|
||||
class Case {
|
||||
friend TestRTT;
|
||||
|
||||
char *filename;
|
||||
char *filename_formatted;
|
||||
protected:
|
||||
TestRTT *node;
|
||||
|
||||
NodeCompat *node;
|
||||
};
|
||||
int id;
|
||||
double rate;
|
||||
unsigned values;
|
||||
unsigned limit; // The number of samples we take per test.
|
||||
|
||||
struct test_rtt {
|
||||
struct Task task; // The periodic task for test_rtt_read()
|
||||
Format *formatter; // The format of the output file
|
||||
std::string filename;
|
||||
std::string filename_formatted;
|
||||
|
||||
public:
|
||||
Case(TestRTT *n, int id, int rate, int values, int limit,
|
||||
const std::string & filename)
|
||||
: node(n), id(id), rate(rate), values(values), limit(limit),
|
||||
filename(filename){};
|
||||
|
||||
int start();
|
||||
int stop();
|
||||
};
|
||||
|
||||
Task task; // The periodic task for test_rtt_read()
|
||||
Format::Ptr 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 between tests.
|
||||
|
||||
int current; // Index of current test in test_rtt::cases
|
||||
int counter;
|
||||
|
||||
struct List cases; // List of test cases
|
||||
std::list<Case> cases; // List of test cases
|
||||
std::list<Case>::iterator current_case;
|
||||
|
||||
char *output; // The directory where we place the results.
|
||||
char *prefix; // An optional prefix in the filename.
|
||||
std::string output; // The directory where we place the results.
|
||||
std::string prefix; // An optional prefix in the filename.
|
||||
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
TestRTT(const uuid_t &id = {}, const std::string &name = "")
|
||||
: Node(id, name), task(CLOCK_MONOTONIC), formatter(nullptr), stream(nullptr), cooldown(0), counter(-1) {}
|
||||
|
||||
virtual ~TestRTT(){};
|
||||
|
||||
virtual int prepare();
|
||||
|
||||
virtual int parse(json_t *json);
|
||||
|
||||
virtual int start();
|
||||
|
||||
virtual int stop();
|
||||
|
||||
virtual std::vector<int> getPollFDs();
|
||||
|
||||
virtual const std::string &getDetails();
|
||||
};
|
||||
|
||||
char *test_rtt_print(NodeCompat *n);
|
||||
|
||||
int test_rtt_parse(NodeCompat *n, json_t *json);
|
||||
|
||||
int test_rtt_prepare(NodeCompat *n);
|
||||
|
||||
int test_rtt_init(NodeCompat *n);
|
||||
|
||||
int test_rtt_destroy(NodeCompat *n);
|
||||
|
||||
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_write(NodeCompat *n, struct Sample *const smps[], unsigned cnt);
|
||||
|
||||
int test_rtt_poll_fds(NodeCompat *n, int fds[]);
|
||||
|
||||
} // namespace node
|
||||
} // namespace villas
|
||||
|
|
|
@ -32,7 +32,7 @@ protected:
|
|||
std::string peer;
|
||||
|
||||
int wait_seconds;
|
||||
Format *format;
|
||||
Format::Ptr formatter;
|
||||
struct CQueueSignalled queue;
|
||||
struct Pool pool;
|
||||
|
||||
|
@ -40,6 +40,8 @@ protected:
|
|||
rtc::Configuration rtcConf;
|
||||
rtc::DataChannelInit dci;
|
||||
|
||||
void onMessage(rtc::binary msg);
|
||||
|
||||
virtual int _read(struct Sample *smps[], unsigned cnt);
|
||||
|
||||
virtual int _write(struct Sample *smps[], unsigned cnt);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <rtc/rtc.hpp>
|
||||
#include <villas/config.hpp>
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/node/config.hpp>
|
||||
#include <villas/nodes/webrtc/signaling_client.hpp>
|
||||
#include <villas/signal_list.hpp>
|
||||
#include <villas/web.hpp>
|
||||
|
@ -25,15 +26,19 @@
|
|||
* But C++ ADL based overload set construction does not find these operators,
|
||||
* if these are invoked in the spdlog/fmt libraries.
|
||||
*
|
||||
* See this issue for a short explaination of ADL errors:
|
||||
* See this issue for a short explanation of ADL errors:
|
||||
* https://github.com/gabime/spdlog/issues/1227#issuecomment-532009129
|
||||
*
|
||||
* Adding the global ::operator<< overload set to the namespace rtc where
|
||||
* the data structures are defined, allows ADL to pick these up in spdlog/fmt.
|
||||
*
|
||||
* Since libdatachannel 0.20, operator<< has been moved into the rtc namespace.
|
||||
*/
|
||||
#if RTC_VERSION < 0x001400
|
||||
namespace rtc {
|
||||
using ::operator<<;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef FMT_LEGACY_OSTREAM_FORMATTER
|
||||
template <>
|
||||
|
@ -49,7 +54,8 @@ class PeerConnection {
|
|||
|
||||
public:
|
||||
PeerConnection(const std::string &server, const std::string &session,
|
||||
const std::string &peer, std::shared_ptr<SignalList> signals,
|
||||
const std::string &peer,
|
||||
std::shared_ptr<SignalList> out_signals,
|
||||
rtc::Configuration config, Web *w, rtc::DataChannelInit d);
|
||||
~PeerConnection();
|
||||
|
||||
|
@ -71,7 +77,7 @@ protected:
|
|||
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<SignalList> out_signals;
|
||||
|
||||
Logger logger;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
// Register API request
|
||||
static char n[] = "config";
|
||||
static char r[] = "/config";
|
||||
static char d[] = "get configuration of this VILLASnode instance";
|
||||
static char d[] = "Get the configuration of this VILLASnode instance";
|
||||
static RequestPlugin<ConfigRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -109,7 +109,7 @@ public:
|
|||
// Register API request
|
||||
static char n[] = "graph";
|
||||
static char r[] = "/graph\\.([a-z]+)";
|
||||
static char d[] = "get graph representation of configuration";
|
||||
static char d[] = "Get graph representation of configuration";
|
||||
static RequestPlugin<GraphRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
// Register API request
|
||||
static char n[] = "node/file";
|
||||
static char r[] = "/node/(" RE_NODE_NAME "|" RE_UUID ")/file(?:/([^/]+))?";
|
||||
static char d[] = "control instances of 'file' node-type";
|
||||
static char d[] = "Control instances of 'file' node-type";
|
||||
static RequestPlugin<FileRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
// Register API request
|
||||
static char n[] = "node";
|
||||
static char r[] = "/node/(" RE_NODE_NAME "|" RE_UUID ")";
|
||||
static char d[] = "retrieve info of a node";
|
||||
static char d[] = "Get node details";
|
||||
static RequestPlugin<NodeInfoRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
// Register API requests
|
||||
static char n[] = "node/stats";
|
||||
static char r[] = "/node/(" RE_NODE_NAME "|" RE_UUID ")/stats";
|
||||
static char d[] = "get internal statistics counters";
|
||||
static char d[] = "Get internal statistics counters";
|
||||
static RequestPlugin<StatsRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
// Register API requests
|
||||
static char n[] = "node/stats/reset";
|
||||
static char r[] = "/node/(" RE_NODE_NAME "|" RE_UUID ")/stats/reset";
|
||||
static char d[] = "reset internal statistics counters";
|
||||
static char d[] = "Reset internal statistics counters";
|
||||
static RequestPlugin<StatsRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
// Register API request
|
||||
static char n[] = "nodes";
|
||||
static char r[] = "/nodes";
|
||||
static char d[] = "retrieve list of all known nodes";
|
||||
static char d[] = "Get list of all known nodes";
|
||||
static RequestPlugin<NodesRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
// Register API request
|
||||
static char n[] = "path";
|
||||
static char r[] = "/path/(" RE_UUID ")";
|
||||
static char d[] = "retrieve info of a path";
|
||||
static char d[] = "Get path details";
|
||||
static RequestPlugin<PathInfoRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
// Register API request
|
||||
static char n[] = "paths";
|
||||
static char r[] = "/paths";
|
||||
static char d[] = "retrieve list of all paths with details";
|
||||
static char d[] = "Get list of all paths with details";
|
||||
static RequestPlugin<PathsRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -113,7 +113,7 @@ std::string RestartRequest::configUri;
|
|||
// Register API request
|
||||
static char n[] = "restart";
|
||||
static char r[] = "/restart";
|
||||
static char d[] = "restart VILLASnode with new configuration";
|
||||
static char d[] = "Restart VILLASnode with new configuration";
|
||||
static RequestPlugin<RestartRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
// Register API request
|
||||
static char n[] = "shutdown";
|
||||
static char r[] = "/shutdown";
|
||||
static char d[] = "quit VILLASnode";
|
||||
static char d[] = "Terminate VILLASnode instance";
|
||||
static RequestPlugin<ShutdownRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -99,7 +99,7 @@ public:
|
|||
// Register API request
|
||||
static char n[] = "status";
|
||||
static char r[] = "/status";
|
||||
static char d[] = "get status and statistics of web server";
|
||||
static char d[] = "Get status and statistics of web server";
|
||||
static RequestPlugin<StatusRequest, n, r, d> p;
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -147,7 +147,7 @@ public:
|
|||
static char n[] = "universal/channel/sample";
|
||||
static char r[] =
|
||||
"/universal/(" RE_NODE_NAME ")/channel/([a-z0-9_-]+)/(sample|event)";
|
||||
static char d[] = "retrieve or send samples via universal data-exchange API";
|
||||
static char d[] = "Retrieve or send samples via universal data-exchange API";
|
||||
static RequestPlugin<ChannelRequest, n, r, d> p;
|
||||
|
||||
} // namespace universal
|
||||
|
|
|
@ -54,7 +54,7 @@ public:
|
|||
// Register API requests
|
||||
static char n[] = "universal/channels";
|
||||
static char r[] = "/universal/(" RE_NODE_NAME ")/channels";
|
||||
static char d[] = "get channels of universal data-exchange API node";
|
||||
static char d[] = "Get channels of universal data-exchange API node";
|
||||
static RequestPlugin<SignalsRequest, n, r, d> p;
|
||||
|
||||
} // namespace universal
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
// Register API requests
|
||||
static char n[] = "universal/info";
|
||||
static char r[] = "/universal/(" RE_NODE_NAME ")/info";
|
||||
static char d[] = "get infos of universal data-exchange API";
|
||||
static char d[] = "Get details of universal data-exchange API";
|
||||
static RequestPlugin<InfoRequest, n, r, d> p;
|
||||
|
||||
} // namespace universal
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
// Register API requests
|
||||
static char n[] = "universal/status";
|
||||
static char r[] = "/universal/(" RE_NODE_NAME ")/status";
|
||||
static char d[] = "get status of universal data-exchange API";
|
||||
static char d[] = "Get status of universal data-exchange API";
|
||||
static RequestPlugin<StatusRequest, n, r, d> p;
|
||||
|
||||
} // namespace universal
|
||||
|
|
|
@ -10,9 +10,6 @@
|
|||
#include <linux/limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <villas/boxes.hpp>
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <villas/config_helper.hpp>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
@ -79,7 +78,7 @@ void Format::start(SignalList::Ptr sigs, int fl) {
|
|||
}
|
||||
|
||||
void Format::start(const std::string &dtypes, int fl) {
|
||||
flags |= fl;
|
||||
flags &= fl;
|
||||
|
||||
signals = std::make_shared<SignalList>(dtypes.c_str());
|
||||
if (!signals)
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cctype>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
|
||||
|
|
|
@ -66,14 +66,14 @@ int ProtobufFormat::sprint(char *buf, size_t len, size_t *wbytes,
|
|||
}
|
||||
|
||||
if (flags & smp->flags & (int)SampleFlags::HAS_TS_ORIGIN) {
|
||||
pb_smp->timestamp = new Villas__Node__Timestamp;
|
||||
if (!pb_smp->timestamp)
|
||||
pb_smp->ts_origin = new Villas__Node__Timestamp;
|
||||
if (!pb_smp->ts_origin)
|
||||
throw MemoryAllocationError();
|
||||
|
||||
villas__node__timestamp__init(pb_smp->timestamp);
|
||||
villas__node__timestamp__init(pb_smp->ts_origin);
|
||||
|
||||
pb_smp->timestamp->sec = smp->ts.origin.tv_sec;
|
||||
pb_smp->timestamp->nsec = smp->ts.origin.tv_nsec;
|
||||
pb_smp->ts_origin->sec = smp->ts.origin.tv_sec;
|
||||
pb_smp->ts_origin->nsec = smp->ts.origin.tv_nsec;
|
||||
}
|
||||
|
||||
pb_smp->n_values = smp->length;
|
||||
|
@ -81,6 +81,11 @@ int ProtobufFormat::sprint(char *buf, size_t len, size_t *wbytes,
|
|||
if (!pb_smp->values)
|
||||
throw MemoryAllocationError();
|
||||
|
||||
if (smp->flags & (int)SampleFlags::NEW_FRAME) {
|
||||
pb_smp->has_new_frame = 1;
|
||||
pb_smp->new_frame = 1;
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < pb_smp->n_values; j++) {
|
||||
Villas__Node__Value *pb_val = pb_smp->values[j] = new Villas__Node__Value;
|
||||
if (!pb_val)
|
||||
|
@ -161,15 +166,19 @@ int ProtobufFormat::sscan(const char *buf, size_t len, size_t *rbytes,
|
|||
if (pb_smp->type != VILLAS__NODE__SAMPLE__TYPE__DATA)
|
||||
throw RuntimeError("Parsed non supported message type. Skipping");
|
||||
|
||||
if (pb_smp->has_new_frame && pb_smp->new_frame) {
|
||||
smp->flags |= (int)SampleFlags::NEW_FRAME;
|
||||
}
|
||||
|
||||
if (pb_smp->has_sequence) {
|
||||
smp->flags |= (int)SampleFlags::HAS_SEQUENCE;
|
||||
smp->sequence = pb_smp->sequence;
|
||||
}
|
||||
|
||||
if (pb_smp->timestamp) {
|
||||
if (pb_smp->ts_origin) {
|
||||
smp->flags |= (int)SampleFlags::HAS_TS_ORIGIN;
|
||||
smp->ts.origin.tv_sec = pb_smp->timestamp->sec;
|
||||
smp->ts.origin.tv_nsec = pb_smp->timestamp->nsec;
|
||||
smp->ts.origin.tv_sec = pb_smp->ts_origin->sec;
|
||||
smp->ts.origin.tv_nsec = pb_smp->ts_origin->nsec;
|
||||
}
|
||||
|
||||
for (j = 0; j < MIN(pb_smp->n_values, smp->capacity); j++) {
|
||||
|
@ -229,5 +238,6 @@ static char d[] = "Google Protobuf";
|
|||
static FormatPlugin<ProtobufFormat, n, d,
|
||||
(int)SampleFlags::HAS_TS_ORIGIN |
|
||||
(int)SampleFlags::HAS_SEQUENCE |
|
||||
(int)SampleFlags::HAS_DATA>
|
||||
(int)SampleFlags::HAS_DATA |
|
||||
(int)SampleFlags::NEW_FRAME>
|
||||
p;
|
||||
|
|
|
@ -10,37 +10,39 @@ syntax = "proto2";
|
|||
package villas.node;
|
||||
|
||||
message Message {
|
||||
repeated Sample samples = 1;
|
||||
repeated Sample samples = 1;
|
||||
}
|
||||
|
||||
message Sample {
|
||||
enum Type {
|
||||
DATA = 1; // Message contains float / integer data values
|
||||
START = 2; // Message marks the beginning of a new simulation case
|
||||
STOP = 3; // Message marks the end of a simulation case
|
||||
};
|
||||
enum Type {
|
||||
DATA = 1; // Message contains float / integer data values
|
||||
START = 2; // Message marks the beginning of a new simulation case
|
||||
STOP = 3; // Message marks the end of a simulation case
|
||||
};
|
||||
|
||||
required Type type = 1 [default = DATA];
|
||||
optional uint64 sequence = 2; // The sequence number is incremented by one for consecutive messages.
|
||||
optional Timestamp timestamp = 4;
|
||||
repeated Value values = 5;
|
||||
required Type type = 1 [default = DATA];
|
||||
optional uint64 sequence = 2; // The sequence number is incremented for consecutive samples.
|
||||
optional Timestamp ts_origin = 3;
|
||||
optional Timestamp ts_received = 4;
|
||||
optional bool new_frame = 5;
|
||||
repeated Value values = 100;
|
||||
}
|
||||
|
||||
message Timestamp {
|
||||
required uint32 sec = 1; // Seconds since 1970-01-01 00:00:00
|
||||
required uint32 nsec = 2; // Nanoseconds of the current second.
|
||||
required uint32 sec = 1; // Seconds since 1970-01-01 00:00:00
|
||||
required uint32 nsec = 2; // Nanoseconds of the current second.
|
||||
}
|
||||
|
||||
message Value {
|
||||
oneof value {
|
||||
double f = 1; // Floating point values.
|
||||
int64 i = 2; // Integer values.
|
||||
bool b = 3; // Boolean values.
|
||||
Complex z = 4; // Complex values.
|
||||
}
|
||||
oneof value {
|
||||
double f = 1; // Floating point values.
|
||||
int64 i = 2; // Integer values.
|
||||
bool b = 3; // Boolean values.
|
||||
Complex z = 4; // Complex values.
|
||||
}
|
||||
}
|
||||
|
||||
message Complex {
|
||||
required float real = 1; // Real component
|
||||
required float imag = 2; // Imaginary component
|
||||
required float real = 1; // Real component
|
||||
required float imag = 2; // Imaginary component
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
|
||||
|
@ -205,6 +204,6 @@ static char d[] = "VILLAS human readable format";
|
|||
static LineFormatPlugin<
|
||||
VILLASHumanFormat, n, d,
|
||||
(int)SampleFlags::HAS_TS_ORIGIN | (int)SampleFlags::HAS_SEQUENCE |
|
||||
(int)SampleFlags::HAS_DATA | (int)SampleFlags::NEW_FRAME,
|
||||
(int)SampleFlags::HAS_DATA | (int)SampleFlags::NEW_FRAME | (int)SampleFlags::HAS_OFFSET,
|
||||
'\n'>
|
||||
p;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include <villas/hook.hpp>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue