From ef62ce0f21915d3710798bd2920921f64e4feba3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:22:50 +0200 Subject: [PATCH 01/43] fix(websocket): Use previous connection state in CLOSED callback The LWS_CALLBACK_CLOSED handler set the connection state to CLOSED and then compared the (now always CLOSED) state against CLOSING, making the check dead code. Save the state before overwriting it so the intended reconnect logic can actually trigger. Signed-off-by: Steffen Vogel --- lib/nodes/websocket.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/nodes/websocket.cpp b/lib/nodes/websocket.cpp index 0a8aa6b53..0ca1f5908 100644 --- a/lib/nodes/websocket.cpp +++ b/lib/nodes/websocket.cpp @@ -230,11 +230,12 @@ int villas::node::websocket_protocol_cb(struct lws *wsi, return -1; - case LWS_CALLBACK_CLOSED: + case LWS_CALLBACK_CLOSED: { + auto old_state = c->state; c->state = websocket_connection::State::CLOSED; c->node->logger->debug("Closed WebSocket connection: {}", c->toString()); - if (c->state != websocket_connection::State::CLOSING) { + if (old_state != websocket_connection::State::CLOSING) { // TODO: Attempt reconnect here } @@ -251,6 +252,7 @@ int villas::node::websocket_protocol_cb(struct lws *wsi, delete c; break; + } case LWS_CALLBACK_CLIENT_WRITEABLE: case LWS_CALLBACK_SERVER_WRITEABLE: { From 427144cc3046a156f259f9099ba4958f651c4d95 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:23:06 +0200 Subject: [PATCH 02/43] fix(file): Disambiguate duplicated in.epoch key in node details string The details string contained 'in.epoch=' twice: once for the epoch mode name and once for the numeric epoch value. Rename the second occurrence to 'in.epoch_value'. Signed-off-by: Steffen Vogel --- lib/nodes/file.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/nodes/file.cpp b/lib/nodes/file.cpp index 3b6166869..a5cd365b7 100644 --- a/lib/nodes/file.cpp +++ b/lib/nodes/file.cpp @@ -183,7 +183,8 @@ char *villas::node::file_print(NodeCompat *n) { strcatf( &buf, - "uri=%s, out.flush=%s, in.skip=%d, in.eof=%s, in.epoch=%s, in.epoch=%.2f", + "uri=%s, out.flush=%s, in.skip=%d, in.eof=%s, in.epoch=%s, " + "in.epoch_value=%.2f", f->uri ? f->uri : f->uri_tmpl, f->flush ? "yes" : "no", f->skip_lines, eof_str, epoch_str, time_to_double(&f->epoch)); From 40d9e72f3216374b379460578a4f2e429aa26017 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:23:17 +0200 Subject: [PATCH 03/43] fix(dumper): Bound copy of socket path into sun_path strcpy() into the fixed-size sun_path buffer could overflow for long socket paths. Use strncpy() and force NUL termination. Signed-off-by: Steffen Vogel --- lib/dumper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/dumper.cpp b/lib/dumper.cpp index 4bc56664b..d2a005c8a 100644 --- a/lib/dumper.cpp +++ b/lib/dumper.cpp @@ -40,7 +40,9 @@ int Dumper::openSocket() { sockaddr_un socketaddrUn; socketaddrUn.sun_family = AF_UNIX; - strcpy(socketaddrUn.sun_path, socketPath.c_str()); + strncpy(socketaddrUn.sun_path, socketPath.c_str(), + sizeof(socketaddrUn.sun_path) - 1); + socketaddrUn.sun_path[sizeof(socketaddrUn.sun_path) - 1] = '\0'; int ret = connect(socketFd, (struct sockaddr *)&socketaddrUn, sizeof(socketaddrUn)); From ceb10a86a3468dff3297a748d969b9034d1525f0 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:23:38 +0200 Subject: [PATCH 04/43] fix(can): Bound copy of interface name into ifr_name strcpy() into the fixed-size ifr_name (IFNAMSIZ) buffer could overflow for long interface names. Use strncpy() and force NUL termination. Signed-off-by: Steffen Vogel --- lib/nodes/can.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/nodes/can.cpp b/lib/nodes/can.cpp index 7191f36f5..2f44857f7 100644 --- a/lib/nodes/can.cpp +++ b/lib/nodes/can.cpp @@ -189,7 +189,8 @@ int villas::node::can_start(NodeCompat *n) { if (c->socket < 0) throw SystemError("Error while opening CAN socket"); - strcpy(ifr.ifr_name, c->interface_name); + strncpy(ifr.ifr_name, c->interface_name, IFNAMSIZ - 1); + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; ret = ioctl(c->socket, SIOCGIFINDEX, &ifr); if (ret != 0) From c43fa09ecc2c8850104f97c76dc011ae9cf0358e Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:23:54 +0200 Subject: [PATCH 05/43] fix(path): Add missing commas in json_pack format string Two 's: b s: b' pairs lacked the separating comma, causing jansson to mis-parse the format and silently drop some path status fields from the API/websocket status output. Signed-off-by: Steffen Vogel --- lib/path.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/path.cpp b/lib/path.cpp index a23e63ede..353449005 100644 --- a/lib/path.cpp +++ b/lib/path.cpp @@ -673,7 +673,8 @@ json_t *Path::toJson() const { json_string(pd->node->getNameShort().c_str())); json_t *json_path = json_pack( - "{ s: s, s: s, s: s, s: b, s: b s: b, s: b, s: b, s: b s: i, s: o, s: o, " + "{ s: s, s: s, s: s, s: b, s: b, s: b, s: b, s: b, s: b, s: i, s: o, s: " + "o, " "s: o, s: o }", "uuid", uuid::toString(uuid).c_str(), "state", stateToString(state).c_str(), "mode", mode == Mode::ANY ? "any" : "all", From 7ad30317c27afa7f0f719e67af87294d1094872c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:24:07 +0200 Subject: [PATCH 06/43] style(utils): Fix typo in tokenize() variable name Rename 'curentPos' to 'currentPos'. Signed-off-by: Steffen Vogel --- common/lib/utils.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/lib/utils.cpp b/common/lib/utils.cpp index 848c607da..5d78a2df5 100644 --- a/common/lib/utils.cpp +++ b/common/lib/utils.cpp @@ -43,14 +43,14 @@ std::vector tokenize(const std::string &s, std::vector tokens; size_t lastPos = 0; - size_t curentPos; + size_t currentPos; - while ((curentPos = s.find(delimiter, lastPos)) != std::string::npos) { - const size_t tokenLength = curentPos - lastPos; + while ((currentPos = s.find(delimiter, lastPos)) != std::string::npos) { + const size_t tokenLength = currentPos - lastPos; tokens.push_back(s.substr(lastPos, tokenLength)); // Advance in string - lastPos = curentPos + delimiter.length(); + lastPos = currentPos + delimiter.length(); } // Check if there's a last token behind the last delimiter. From 1cd77a8268a53eec583384da8adbff71e83f9d70 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:24:22 +0200 Subject: [PATCH 07/43] fix(utils): Handle vasprintf/realloc failure in vstrcatf The original code overwrote *dest with the result of realloc() without checking for NULL, leaking the old buffer and then copying into a NULL pointer. Also handle vasprintf() failure. On allocation failure the old buffer is preserved and returned unchanged. Signed-off-by: Steffen Vogel --- common/lib/utils.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/common/lib/utils.cpp b/common/lib/utils.cpp index 5d78a2df5..18120d227 100644 --- a/common/lib/utils.cpp +++ b/common/lib/utils.cpp @@ -198,9 +198,17 @@ char *vstrcatf(char **dest, const char *fmt, va_list ap) { int n = *dest ? strlen(*dest) : 0; int i = vasprintf(&tmp, fmt, ap); - *dest = (char *)(realloc(*dest, n + i + 1)); - if (*dest != nullptr) - strncpy(*dest + n, tmp, i + 1); + if (i < 0) + return *dest; + + char *p = (char *)realloc(*dest, n + i + 1); + if (p == nullptr) { + free(tmp); + return *dest; + } + + *dest = p; + strncpy(*dest + n, tmp, i + 1); free(tmp); From 03e050a14cfe2d00428d9ea4f17a132cadf0746f Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:27:43 +0200 Subject: [PATCH 08/43] fix(api): Correct capabilities request file and description spelling Rename requests/capabiltities.cpp to requests/capabilities.cpp and fix the 'capabiltities'/'ressource' misspellings in its comment and API description string (visible in the API index). Signed-off-by: Steffen Vogel --- lib/api/CMakeLists.txt | 2 +- lib/api/requests/{capabiltities.cpp => capabilities.cpp} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename lib/api/requests/{capabiltities.cpp => capabilities.cpp} (90%) diff --git a/lib/api/CMakeLists.txt b/lib/api/CMakeLists.txt index 1a0cdd2d8..908230663 100644 --- a/lib/api/CMakeLists.txt +++ b/lib/api/CMakeLists.txt @@ -14,7 +14,7 @@ set(API_SRC requests/path.cpp requests/status.cpp - requests/capabiltities.cpp + requests/capabilities.cpp requests/config.cpp requests/shutdown.cpp requests/restart.cpp diff --git a/lib/api/requests/capabiltities.cpp b/lib/api/requests/capabilities.cpp similarity index 90% rename from lib/api/requests/capabiltities.cpp rename to lib/api/requests/capabilities.cpp index 6a7861862..211e1c9be 100644 --- a/lib/api/requests/capabiltities.cpp +++ b/lib/api/requests/capabilities.cpp @@ -1,4 +1,4 @@ -/* The "capabiltities" API ressource. +/* The "capabilities" API resource. * * Author: Steffen Vogel * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University @@ -36,7 +36,7 @@ class CapabilitiesRequest : public Request { static char n[] = "capabilities"; static char r[] = "/capabilities"; static char d[] = - "get capabiltities and details about this VILLASnode instance"; + "get capabilities and details about this VILLASnode instance"; static RequestPlugin p; } // namespace api From 796c8304338737dba2f389b6e4b48fcaa3bdc916 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:27:59 +0200 Subject: [PATCH 09/43] fix(python): Avoid mutable default, init child, use self.config in Node Three issues in the Python Node client: - config={} was a mutable default argument; use None and create a dict. - The api_url deduction read the 'config' parameter instead of self.config, ignoring a config loaded from config_filename. - self.child was only created in start(), so is_running() before start() raised AttributeError; initialize it to None. Signed-off-by: Steffen Vogel --- python/villas/node/node.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/villas/node/node.py b/python/villas/node/node.py index e17740dd1..c8eb9510a 100644 --- a/python/villas/node/node.py +++ b/python/villas/node/node.py @@ -25,13 +25,14 @@ def __init__( api_url=None, log_filename=None, config_filename=None, - config={}, + config=None, executable="villas-node", **kwargs, ): self.api_url = api_url self.log_filename = log_filename self.executable = executable + self.child = None if config_filename and config: raise RuntimeError( @@ -42,11 +43,11 @@ def __init__( with open(config_filename) as f: self.config = json.load(f) else: - self.config = config + self.config = config if config is not None else {} # Try to deduct api_url from config if self.api_url is None: - port = config.get("http", {}).get("port") + port = self.config.get("http", {}).get("port") if port is None: port = 80 if os.getuid() == 0 else 8080 From 4986c0822472984e7e75987d36a7ca5e9c5c42aa Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:28:11 +0200 Subject: [PATCH 10/43] fix(python): Only join started threads in communicate() rt/st were only bound when the corresponding callback was provided, so calling communicate() with a single callback raised UnboundLocalError when wait=True. Initialize to None and join conditionally. Signed-off-by: Steffen Vogel --- python/villas/node/communicate.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/villas/node/communicate.py b/python/villas/node/communicate.py index f01a05146..df6b92053 100644 --- a/python/villas/node/communicate.py +++ b/python/villas/node/communicate.py @@ -67,17 +67,21 @@ def communicate( send_cb: SendCallback | None = None, wait: bool = True, ): + rt = None if recv_cb is not None: rt = RecvThread(recv_cb) rt.start() + st = None if send_cb is not None: st = SendThread(send_cb, rate) st.start() if wait: try: - rt.join() - st.join() + if rt is not None: + rt.join() + if st is not None: + st.join() except KeyboardInterrupt: logger.info("Received Ctrl+C. Stopping send/recv threads") From 495d45062ded6553e60003e42cae80f087a3f104 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:28:20 +0200 Subject: [PATCH 11/43] fix(python): Assign stripped string in VillasHuman.loads() str.strip() returns a new string; the previous code discarded the result making the strip a no-op. Assign it back to s. Signed-off-by: Steffen Vogel --- python/villas/node/formats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/villas/node/formats.py b/python/villas/node/formats.py index c5e7b355a..5596f6a47 100644 --- a/python/villas/node/formats.py +++ b/python/villas/node/formats.py @@ -120,7 +120,7 @@ def loads(self, s: str) -> list[Sample]: Load samples from a string. """ - s.strip(self.separator + self.delimiter) + s = s.strip(self.separator + self.delimiter) sample_strs = s.split(sep=self.delimiter) samples = (self.load_sample(sample) for sample in sample_strs) return [s for s in samples if s is not None] From 383dedf50d6556c317b26cef1def9d6393985b6c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:29:04 +0200 Subject: [PATCH 12/43] fix(tools): Correct several issues in tc-netem.sh - Use mark 124 (not 123) for the reverse-path POSTROUTING SNAT rule so reverse traffic actually matches the mark set in PREROUTING. - Use the correct loop variable $inf (was $if) in the debug output. - Quote $DEBUG in the non-empty test to avoid 'unary operator expected'. - Replace 'exit -1' (yields 255) with 'exit 1' in die(). Signed-off-by: Steffen Vogel --- tools/tc-netem.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/tc-netem.sh b/tools/tc-netem.sh index b8241feda..2a734b3c1 100755 --- a/tools/tc-netem.sh +++ b/tools/tc-netem.sh @@ -9,7 +9,7 @@ # SPDX-License-Identifier: Apache-2.0 set -e # Abort on error -die() { echo "$1"; exit -1; } +die() { echo "$1"; exit 1; } # Apply netem qdisc also for reverse path REVERSE=0 @@ -75,7 +75,7 @@ if (( $REVERSE )); then $NF -t nat -I PREROUTING $FILTER_REV -j mark --mark-set 124 --mark-target CONTINUE $NF -t nat -I PREROUTING $FILTER_REV -j dnat --to-dst $SRC --dnat-target CONTINUE - $NF -t nat -I POSTROUTING --mark 123 -j snat --to-src $MY + $NF -t nat -I POSTROUTING --mark 124 -j snat --to-src $MY # Add classful qdisc to egress (outgoing) network device $TC qdisc replace dev $SRC_IF root handle 4000 prio bands 4 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 @@ -92,7 +92,7 @@ if (( $REVERSE )); then fi # Some debug and status output -if [ -n $DEBUG ]; then +if [ -n "$DEBUG" ]; then if [ "$SRC_IF" == "$DST_IF" ]; then IFNS="$SRC_IF" else @@ -101,7 +101,7 @@ if [ -n $DEBUG ]; then for inf in $IFNS; do for cmd in qdisc filter class; do - echo -e "\nTC ==> $if: $cmd" + echo -e "\nTC ==> $inf: $cmd" tc -d -p $cmd show dev $inf done done From d97ed20623e218196335be71696bd863c61bb2a8 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:29:25 +0200 Subject: [PATCH 13/43] fix(tools): Remove stray exits and fix debug output in tc-netem2.sh - Remove two leftover 'exit' statements that aborted the script before the qdisc/filter setup ran. - Use the correct loop variable $inf (was $if) and quote $DEBUG in the debug output. Signed-off-by: Steffen Vogel --- tools/tc-netem2.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/tc-netem2.sh b/tools/tc-netem2.sh index e4f59592c..cb08a23d6 100755 --- a/tools/tc-netem2.sh +++ b/tools/tc-netem2.sh @@ -56,8 +56,6 @@ modprobe sch_netem || die "The netem qdisc is not compiled in this kernel!" $NF -t nat -F $NF -t nat -X -exit - # Add new chain, mark packets from $SRC and redirect them to $DEST # Insert new chain into flow @@ -67,8 +65,6 @@ $NF -t nat -A PREROUTING -i $SRC_IF -s $SRC -j dnat --to-dst $DST --dnat-target $NF -t nat -A PREROUTING -i $DST_IF -s $DST -j mark --mark-set $MARK --mark-target CONTINUE $NF -t nat -A PREROUTING -i $DST_IF -s $DST -j dnat --to-dst $SRC --dnat-target ACCEPT -exit - # Clean traffic control $TC qdisc delete dev $DST_IF root || true @@ -86,7 +82,7 @@ if (( $REVERSE )); then echo -e " $NETEM_REV" fi -if [ -n $DEBUG ]; then +if [ -n "$DEBUG" ]; then if [ "$SRC_IF" == "$DST_IF" ]; then IFNS="$SRC_IF" else @@ -95,7 +91,7 @@ if [ -n $DEBUG ]; then for inf in $IFNS; do for cmd in qdisc filter class; do - echo -e "\nTC ==> $if: $cmd" + echo -e "\nTC ==> $inf: $cmd" tc -d -p $cmd show dev $inf done done From bf24319484b30da27729afe7f64def5836f569ee Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:29:35 +0200 Subject: [PATCH 14/43] fix(tools): Include .h headers in format-all.sh glob The pattern '.h' lacked the leading wildcard, so plain C headers were never selected for clang-format. Use '*.h'. Signed-off-by: Steffen Vogel --- tools/format-all.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/format-all.sh b/tools/format-all.sh index 0d90f377f..9c16d7ad0 100755 --- a/tools/format-all.sh +++ b/tools/format-all.sh @@ -6,5 +6,5 @@ # SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University # SPDX-License-Identifier: Apache-2.0 -git ls-files -c -z -- "*.c" ".h" "*.hpp" "*.cpp" ":!:fpga/thirdparty" |\ +git ls-files -c -z -- "*.c" "*.h" "*.hpp" "*.cpp" ":!:fpga/thirdparty" |\ xargs -0 clang-format --verbose -i From 3a654561ad7dd863716b3f95e98d3c1f4dc1c673 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:29:58 +0200 Subject: [PATCH 15/43] fix(tools): Return explicit success and fix exit code in pre-commit hook - format_file() now returns 0 explicitly so a well-formatted (or non-existent) file is not miscounted as 'reformatted'. - Quote file paths. - Use exit 1 instead of exit -1 (255). Signed-off-by: Steffen Vogel --- tools/git-pre-commit-hook.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/git-pre-commit-hook.sh b/tools/git-pre-commit-hook.sh index f6237b56a..fbfe8934c 100755 --- a/tools/git-pre-commit-hook.sh +++ b/tools/git-pre-commit-hook.sh @@ -8,12 +8,13 @@ format_file() { FILE="${1}" - if [ -f ${FILE} ]; then - if ! clang-format --Werror --dry-run ${FILE}; then - clang-format -i ${FILE} + if [ -f "${FILE}" ]; then + if ! clang-format --Werror --dry-run "${FILE}"; then + clang-format -i "${FILE}" return 1 fi fi + return 0 } case "${1}" in @@ -37,7 +38,7 @@ case "${1}" in if (( ${CHANGES} > 0 )); then echo "Formatting of ${CHANGES} files has been fixed. Please stage and commit again." - exit -1 + exit 1 fi ;; esac From 43ac58bc140c2c483b3ad154aa1616c49ed05679 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:30:10 +0200 Subject: [PATCH 16/43] fix(tools): Quote $@ in villas-helper.sh wrapper Unquoted $@ word-splits arguments containing spaces. Use "$@". Signed-off-by: Steffen Vogel --- tools/villas-helper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/villas-helper.sh b/tools/villas-helper.sh index bd1867e5d..a9b781659 100755 --- a/tools/villas-helper.sh +++ b/tools/villas-helper.sh @@ -35,5 +35,5 @@ function colorize() { function villas() { VILLAS_LOG_PREFIX=${VILLAS_LOG_PREFIX:-$(colorize "[$1-$((${RANDOM} % 100))} ")} \ - command villas $@ + command villas "$@" } From 772ec4b9965d4076d12be66a9e9b836c240cdf23 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:30:36 +0200 Subject: [PATCH 17/43] fix(tools): Port villas-api.sh to the VILLASnode API v2 The script targeted the legacy v1 relay API (http://localhost:80/api/v1) and used the old action/id/request POST envelope. The node mounts its API at /api/v2 and uses plain REST endpoints. Update the default endpoint to http://localhost:8080/api/v2 and issue proper GET/POST requests against /{action}. Signed-off-by: Steffen Vogel --- tools/villas-api.sh | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/tools/villas-api.sh b/tools/villas-api.sh index 82c9543ac..20a5f1623 100755 --- a/tools/villas-api.sh +++ b/tools/villas-api.sh @@ -21,13 +21,25 @@ fi ACTION=$1 REQUEST=${2:-\{\}} -ID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) -ENDPOINT=${ENDPOINT:-http://localhost:80/api/v1} +ENDPOINT=${ENDPOINT:-http://localhost:8080/api/v2} -echo "Issuing API request: action=${ACTION}, id=${ID}, request=${REQUEST}, endpoint=${ENDPOINT}" +# GET actions have no body; actions carrying a request body use POST +case "${ACTION}" in + status|capabilities|config|nodes|paths) + METHOD=GET + ;; + *) + METHOD=POST + ;; +esac -curl -s -X POST --data "{ - \"action\" : \"${ACTION}\", - \"id\": \"${ID}\", - \"request\": ${REQUEST} -}" ${ENDPOINT} | jq . +echo "Issuing API request: ${METHOD} ${ENDPOINT}/${ACTION}, request=${REQUEST}" + +if [ "${METHOD}" = "GET" ]; then + curl -s "${ENDPOINT}/${ACTION}" | jq . +else + curl -s -X POST \ + -H "Content-Type: application/json" \ + --data "${REQUEST}" \ + "${ENDPOINT}/${ACTION}" | jq . +fi From a05580e8337ce16d6cf941db196580782bc3535c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:30:52 +0200 Subject: [PATCH 18/43] fix(shmem-client): Show required RNAME argument in usage line The usage string omitted the mandatory RNAME argument even though the program requires exactly 3 arguments (argc != 4 check) and documents RNAME in the argument list. Signed-off-by: Steffen Vogel --- clients/shmem/villas-shmem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/shmem/villas-shmem.cpp b/clients/shmem/villas-shmem.cpp index a39d975fa..f76ca4c3d 100644 --- a/clients/shmem/villas-shmem.cpp +++ b/clients/shmem/villas-shmem.cpp @@ -36,7 +36,7 @@ class Shmem : public Tool { void usage() override { std::cout - << "Usage: villas-test-shmem WNAME VECTORIZE" << std::endl + << "Usage: villas-test-shmem WNAME RNAME VECTORIZE" << std::endl << " WNAME name of the shared memory object for the output queue" << std::endl << " RNAME name of the shared memory object for the input queue" From dc7f5ae135d69bc24558795dd80c92b30d12d042 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:31:12 +0200 Subject: [PATCH 19/43] fix(packaging): Report correct parameter and fix typos in deps.sh - should_build() printed '$2' (use) instead of the offending '$3' (requirement) in its error message. - Fix 'dependendency' and "wan't" typos. Signed-off-by: Steffen Vogel --- packaging/deps.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packaging/deps.sh b/packaging/deps.sh index d3270a27a..c11ab556a 100644 --- a/packaging/deps.sh +++ b/packaging/deps.sh @@ -23,7 +23,7 @@ should_build() { optional) ;; required) ;; *) - echo >&2 "Error: invalid parameter '$2' for should_build. should be one of 'optional' and 'required', default is 'optional'" + echo >&2 "Error: invalid parameter '$3' for should_build. should be one of 'optional' and 'required', default is 'optional'" exit 1 ;; esac @@ -31,7 +31,7 @@ should_build() { local deps="${@:4}" if [[ -n "${DEPS_SCAN+x}" ]]; then - echo "${requirement} dependendency ${id} should be installed ${use}." + echo "${requirement} dependency ${id} should be installed ${use}." [[ -n "${deps[*]}" ]] && echo " transitive dependencies: ${deps}" echo return 1 @@ -45,7 +45,7 @@ should_build() { if [[ -z "${DEPS_NONINTERACTIVE+x}" ]] && [[ -t 1 ]]; then echo - read -p "Do you wan't to install '${id}' into '${PREFIX}'? This is used ${use}. (y/N) " + read -p "Do you want to install '${id}' into '${PREFIX}'? This is used ${use}. (y/N) " case "${REPLY}" in y | Y) echo "Installing '${id}'" From 145e49ade53101dad6b7ee8525fb8ca2be94cdd5 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:31:32 +0200 Subject: [PATCH 20/43] fix(lua): Correct SampleFlags bit-shift comments in test hook The flag comments were off by one (e.g. value 1 labelled '(1 << 1)') and NEW_SIMULATION (131072) was labelled '(1 << 16)' (it's 1 << 17) and duplicated NEW_FRAME's description. Signed-off-by: Steffen Vogel --- lua/hooks/test.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lua/hooks/test.lua b/lua/hooks/test.lua index 9a1fcd765..766c8dc0a 100644 --- a/lua/hooks/test.lua +++ b/lua/hooks/test.lua @@ -15,14 +15,14 @@ Reason = { } SampleFlags = { - HAS_TS_ORIGIN = 1, -- "(1 << 1)" Include origin timestamp in output. - HAS_TS_RECEIVED = 2, -- "(1 << 2)" Include receive timestamp in output. - HAS_OFFSET = 4, -- "(1 << 3)" Include offset (received - origin timestamp) in output. - HAS_SEQUENCE = 8, -- "(1 << 4)" Include sequence number in output. - HAS_DATA = 16, -- "(1 << 5)" Include values in output. - - NEW_FRAME = 65536, -- "(1 << 16)" This sample is the first of a new simulation case - NEW_SIMULATION = 131072, -- "(1 << 16)" This sample is the first of a new simulation case + HAS_TS_ORIGIN = 1, -- "(1 << 0)" Include origin timestamp in output. + HAS_TS_RECEIVED = 2, -- "(1 << 1)" Include receive timestamp in output. + HAS_OFFSET = 4, -- "(1 << 2)" Include offset (received - origin timestamp) in output. + HAS_SEQUENCE = 8, -- "(1 << 3)" Include sequence number in output. + HAS_DATA = 16, -- "(1 << 4)" Include values in output. + + NEW_FRAME = 65536, -- "(1 << 16)" This sample is the first of a new frame + NEW_SIMULATION = 131072, -- "(1 << 17)" This sample is the first of a new simulation case ALL = 2147483647, -- "INT_MAX" Enable all output options. } From 152e52be57fed457f02ca9607be476dfe541d94d Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:32:12 +0200 Subject: [PATCH 21/43] fix(tools): Correct comment typos, author email and whitelist in hwdef-parse.py - Fix 'Ignroing unkown' comment, 'VLNI' -> 'VLNV' and close the unterminated author email angle bracket. - Remove duplicated axis_register_slice whitelist entry. Signed-off-by: Steffen Vogel --- tools/hwdef-parse.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/hwdef-parse.py b/tools/hwdef-parse.py index b3ca7c7ec..bb5f8e9ce 100755 --- a/tools/hwdef-parse.py +++ b/tools/hwdef-parse.py @@ -6,7 +6,7 @@ Author: Daniel Krebs Author: Hatim Kanchwala Author: Pascal Bauer -Author: Niklas Eiling SPDX-FileCopyrightText: 2017-2022 Steffen Vogel SPDX-FileCopyrightText: 2017-2022 Daniel Krebs SPDX-FileCopyrightText: 2017-2022 Hatim Kanchwala @@ -63,7 +63,7 @@ ["acs.eonerc.rwth-aachen.de", "sysgen"], ] -# List of VLNI ids of AXI4-Stream infrastructure IP cores +# List of VLNV ids of AXI4-Stream infrastructure IP cores # which do not alter data see # PG085 (AXI4-Stream Infrastructure IP Suite v2.2) axi_converter_whitelist = [ @@ -71,7 +71,6 @@ ["xilinx.com", "ip", "axis_clock_converter"], ["xilinx.com", "ip", "axis_register_slice"], ["xilinx.com", "ip", "axis_dwidth_converter"], - ["xilinx.com", "ip", "axis_register_slice"], ["xilinx.com", "ip", "axis_data_fifo"], ["xilinx.com", "ip", "floating_point"], ["xilinx.com", "module_ref", "prepend_seqnum"], @@ -160,7 +159,7 @@ def sanitize_name(name): instance = module.get("INSTANCE") vlnv = module.get("VLNV") - # Ignroing unkown + # Ignoring IPs not present in the whitelist if not vlnv_match(vlnv, whitelist): continue From 70d0f916c301bb4c41910f0fc37d630e49bf6bd5 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:33:38 +0200 Subject: [PATCH 22/43] fix: Correct various spelling mistakes in comments and messages Fix typos across headers and sources: - desciplines/seperately -> disciplines/separately (tc, tc_netem) - seperated/inferface -> separated/interface (socket_addr) - occured/occurences -> occurred/occurrences (shmem, list, line, utils) - precission/destionations -> precision/destinations (utils) - Compatability -> Compatibility (compat, vfio_container, node_compat, web) - intialize/initilize/de-intialize -> initialize/.../de-initialize (villas-signal, villas-pipe, villas-hook, websocket) - 'The the' / 'for for' duplicate words (utils.hpp, kernel/if) Signed-off-by: Steffen Vogel --- common/include/villas/compat.hpp | 2 +- common/include/villas/kernel/vfio_container.hpp | 2 +- common/include/villas/list.hpp | 4 ++-- common/include/villas/utils.hpp | 6 +++--- common/lib/compat.cpp | 2 +- common/lib/kernel/vfio_container.cpp | 2 +- common/lib/utils.cpp | 2 +- include/villas/kernel/tc.hpp | 4 ++-- include/villas/kernel/tc_netem.hpp | 2 +- include/villas/node_compat.hpp | 2 +- include/villas/shmem.hpp | 2 +- include/villas/socket_addr.hpp | 2 +- include/villas/web.hpp | 2 +- lib/formats/line.cpp | 4 ++-- lib/kernel/if.cpp | 4 ++-- lib/nodes/websocket.cpp | 2 +- src/villas-hook.cpp | 2 +- src/villas-pipe.cpp | 2 +- src/villas-signal.cpp | 4 ++-- 19 files changed, 26 insertions(+), 26 deletions(-) diff --git a/common/include/villas/compat.hpp b/common/include/villas/compat.hpp index 757e46ae8..7b8e84a9a 100644 --- a/common/include/villas/compat.hpp +++ b/common/include/villas/compat.hpp @@ -1,4 +1,4 @@ -/* Compatability for different library versions. +/* Compatibility for different library versions. * * Author: Steffen Vogel * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University diff --git a/common/include/villas/kernel/vfio_container.hpp b/common/include/villas/kernel/vfio_container.hpp index d1a27c652..e9ef36b7d 100644 --- a/common/include/villas/kernel/vfio_container.hpp +++ b/common/include/villas/kernel/vfio_container.hpp @@ -24,7 +24,7 @@ namespace villas { namespace kernel { namespace vfio { -// Backwards compatability with older kernels +// Backwards compatibility with older kernels #ifdef VFIO_UPDATE_VADDR static constexpr size_t EXTENSION_SIZE = VFIO_UPDATE_VADDR + 1; #elif defined(VFIO_UNMAP_ALL) diff --git a/common/include/villas/list.hpp b/common/include/villas/list.hpp index d09447b00..48b972b49 100644 --- a/common/include/villas/list.hpp +++ b/common/include/villas/list.hpp @@ -64,7 +64,7 @@ void list_push(struct List *l, void *p); // Clear list. void list_clear(struct List *l); -// Remove all occurences of a list item. +// Remove all occurrences of a list item. void list_remove_all(struct List *l, void *p); int list_remove(struct List *l, size_t idx); @@ -74,7 +74,7 @@ int list_insert(struct List *l, size_t idx, void *p); // Return the first element of the list for which cmp returns zero. void *list_search(struct List *l, cmp_cb_t cmp, const void *ctx); -// Returns the number of occurences for which cmp returns zero when called on all list elements. +// Returns the number of occurrences for which cmp returns zero when called on all list elements. int list_count(struct List *l, cmp_cb_t cmp, void *ctx); // Return 0 if list contains pointer p. diff --git a/common/include/villas/utils.hpp b/common/include/villas/utils.hpp index 0919013bf..7807f29ff 100644 --- a/common/include/villas/utils.hpp +++ b/common/include/villas/utils.hpp @@ -66,18 +66,18 @@ char *decolor(char *str); // @return Normal variate random variable (Gaussian) double boxMuller(float m, float s); -// Double precission uniform random variable +// Double precision uniform random variable double randf(); // Concat formatted string to an existing string. // // This function uses realloc() to resize the destination. -// Please make sure to only on dynamic allocated destionations!!! +// Please make sure to only use it on dynamically allocated destinations!!! // // @param dest A pointer to a malloc() allocated memory region // @param fmt A format string like for printf() // @param ... Optional parameters like for printf() -// @retval The the new value of the dest buffer. +// @retval The new value of the dest buffer. char *strcatf(char **dest, const char *fmt, ...) __attribute__((format(printf, 2, 3))); diff --git a/common/lib/compat.cpp b/common/lib/compat.cpp index 1197643b0..8a0b391d0 100644 --- a/common/lib/compat.cpp +++ b/common/lib/compat.cpp @@ -1,4 +1,4 @@ -/* Compatability for different library versions. +/* Compatibility for different library versions. * * Author: Steffen Vogel * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University diff --git a/common/lib/kernel/vfio_container.cpp b/common/lib/kernel/vfio_container.cpp index e329443e4..989759dd9 100644 --- a/common/lib/kernel/vfio_container.cpp +++ b/common/lib/kernel/vfio_container.cpp @@ -57,7 +57,7 @@ static std::array construct_vfio_extension_str() { ret[VFIO_SPAPR_TCE_v2_IOMMU] = "SPAPR TCE v2"; // cppcheck-suppress containerOutOfBounds ret[VFIO_NOIOMMU_IOMMU] = "No IOMMU"; -// Backwards compatability with older kernels +// Backwards compatibility with older kernels #ifdef VFIO_UNMAP_ALL ret[VFIO_UNMAP_ALL] = "Unmap all"; #endif diff --git a/common/lib/utils.cpp b/common/lib/utils.cpp index 18120d227..e45f816e4 100644 --- a/common/lib/utils.cpp +++ b/common/lib/utils.cpp @@ -159,7 +159,7 @@ char *decolor(char *str) { } void killme(int sig) { - // Send only to main thread in case the ID was initilized by signalsInit() + // Send only to main thread in case the ID was initialized by signalsInit() if (main_thread) pthread_kill(main_thread, sig); else diff --git a/include/villas/kernel/tc.hpp b/include/villas/kernel/tc.hpp index 51de653d3..5dd8266bf 100644 --- a/include/villas/kernel/tc.hpp +++ b/include/villas/kernel/tc.hpp @@ -1,9 +1,9 @@ -/* Setup interface queuing desciplines for network emulation. +/* Setup interface queuing disciplines for network emulation. * * We use the firewall mark to apply individual netem qdiscs * per node. Every node uses an own BSD socket. * By using so SO_MARK socket option (see socket(7)) - * we can classify traffic originating from a node seperately. + * we can classify traffic originating from a node separately. * * Author: Steffen Vogel * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University diff --git a/include/villas/kernel/tc_netem.hpp b/include/villas/kernel/tc_netem.hpp index f2368bb5a..2e7006765 100644 --- a/include/villas/kernel/tc_netem.hpp +++ b/include/villas/kernel/tc_netem.hpp @@ -3,7 +3,7 @@ * We use the firewall mark to apply individual netem qdiscs * per node. Every node uses an own BSD socket. * By using so SO_MARK socket option (see socket(7)) - * we can classify traffic originating from a node seperately. + * we can classify traffic originating from a node separately. * * Author: Steffen Vogel * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University diff --git a/include/villas/node_compat.hpp b/include/villas/node_compat.hpp index caa5039e8..0b9f5de57 100644 --- a/include/villas/node_compat.hpp +++ b/include/villas/node_compat.hpp @@ -1,4 +1,4 @@ -/* Node compatability layer for C++. +/* Node compatibility layer for C++. * * Author: Steffen Vogel * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University diff --git a/include/villas/shmem.hpp b/include/villas/shmem.hpp index 17119deeb..3be6fe15f 100644 --- a/include/villas/shmem.hpp +++ b/include/villas/shmem.hpp @@ -56,7 +56,7 @@ struct ShmemInterface { * calls will be written to this pointer. * @param[in] conf Configuration parameters for the output queue. * @retval 0 The objects were opened and initialized successfully. - * @retval <0 An error occured; errno is set accordingly. + * @retval <0 An error occurred; errno is set accordingly. */ int shmem_int_open(const char *wname, const char *rname, struct ShmemInterface *shm, struct ShmemConfig *conf); diff --git a/include/villas/socket_addr.hpp b/include/villas/socket_addr.hpp index d648cf64b..8dd83bc90 100644 --- a/include/villas/socket_addr.hpp +++ b/include/villas/socket_addr.hpp @@ -40,7 +40,7 @@ enum class SocketLayer { ETH, IP, UDP, UNIX, TCP_CLIENT, TCP_SERVER }; /* Generate printable socket address depending on the address family * * A IPv4 address is formatted as dotted decimals followed by the port/protocol number - * A link layer address is formatted in hexadecimals digits seperated by colons and the inferface name + * A link layer address is formatted in hexadecimals digits separated by colons and the interface name * * @param sa A pointer to the socket address. * @return The buffer containing the textual representation of the address. The caller is responsible to free() this buffer! diff --git a/include/villas/web.hpp b/include/villas/web.hpp index 6fd649d72..894feb1e7 100644 --- a/include/villas/web.hpp +++ b/include/villas/web.hpp @@ -67,7 +67,7 @@ class Web final { Api *getApi() { return api; } - // for C-compatability + // for C-compatibility lws_context *getContext() { return context; } lws_vhost *getVHost() { return vhost; } diff --git a/lib/formats/line.cpp b/lib/formats/line.cpp index 1e15715a8..b4af854d2 100644 --- a/lib/formats/line.cpp +++ b/lib/formats/line.cpp @@ -92,7 +92,7 @@ int LineFormat::scan(FILE *f, struct Sample *const smps[], unsigned cnt) { if (!first_line_skipped) { bytes = getdelim(&in.buffer, &in.buflen, delimiter, f); if (bytes < 0) - return -1; // An error or eof occured + return -1; // An error or EOF occurred first_line_skipped = true; } @@ -107,7 +107,7 @@ int LineFormat::scan(FILE *f, struct Sample *const smps[], unsigned cnt) { if (feof(f)) break; else if (bytes < 0) - return -1; // An error or eof occured + return -1; // An error or EOF occurred // Skip whitespaces, empty and comment lines for (ptr = in.buffer; isspace(*ptr); ptr++) diff --git a/lib/kernel/if.cpp b/lib/kernel/if.cpp index 71ae1a9d5..8f7e6ceb9 100644 --- a/lib/kernel/if.cpp +++ b/lib/kernel/if.cpp @@ -183,7 +183,7 @@ int Interface::setAffinity(int affinity) { if (file) { if (fprintf(file, "%8lx", (unsigned long)cset_pin) < 0) throw SystemError( - "Failed to set affinity for for IRQ {} on interface '{}'", irq, + "Failed to set affinity for IRQ {} on interface '{}'", irq, getName()); fclose(file); @@ -192,7 +192,7 @@ int Interface::setAffinity(int affinity) { (std::string)cset_pin); } else throw SystemError( - "Failed to set affinity for for IRQ {} on interface '{}'", irq, + "Failed to set affinity for IRQ {} on interface '{}'", irq, getName()); } diff --git a/lib/nodes/websocket.cpp b/lib/nodes/websocket.cpp index 0ca1f5908..bf6b78bb5 100644 --- a/lib/nodes/websocket.cpp +++ b/lib/nodes/websocket.cpp @@ -206,7 +206,7 @@ int villas::node::websocket_protocol_cb(struct lws *wsi, websocket_connection_close(c, wsi, LWS_CLOSE_STATUS_POLICY_VIOLATION, "Internal error"); c->node->logger->warn( - "Failed to intialize WebSocket connection: reason={}", ret); + "Failed to initialize WebSocket connection: reason={}", ret); return -1; } diff --git a/src/villas-hook.cpp b/src/villas-hook.cpp index 24e33d33f..807e8577e 100644 --- a/src/villas-hook.cpp +++ b/src/villas-hook.cpp @@ -199,7 +199,7 @@ class Hook : public Tool { ret = pool_init(&p, 10 * cnt, SAMPLE_LENGTH(DEFAULT_SAMPLE_LENGTH)); if (ret) - throw RuntimeError("Failed to initilize memory pool"); + throw RuntimeError("Failed to initialize memory pool"); // Initialize IO struct desc { diff --git a/src/villas-pipe.cpp b/src/villas-pipe.cpp index ca800d7a5..53a6477d9 100644 --- a/src/villas-pipe.cpp +++ b/src/villas-pipe.cpp @@ -447,7 +447,7 @@ class Pipe : public Tool { ret = node->getFactory()->start(&sn); if (ret) - throw RuntimeError("Failed to intialize node type {}: reason={}", + throw RuntimeError("Failed to initialize node type {}: reason={}, node->getFactory()->getName(), ret); sn.startInterfaces(); diff --git a/src/villas-signal.cpp b/src/villas-signal.cpp index f5161cf73..c5096bab5 100644 --- a/src/villas-signal.cpp +++ b/src/villas-signal.cpp @@ -241,7 +241,7 @@ class Signal : public Tool { ret = node->getFactory()->start(nullptr); if (ret) - throw RuntimeError("Failed to intialize node type {}: reason={}", + throw RuntimeError("Failed to initialize node type {}: reason={}", node->getFactory()->getName(), ret); ret = node->check(); @@ -295,7 +295,7 @@ class Signal : public Tool { ret = node->getFactory()->stop(); if (ret) - throw RuntimeError("Failed to de-intialize node type {}: reason={}", + throw RuntimeError("Failed to de-initialize node type {}: reason={}", node->getFactory()->getName(), ret); delete node; From c5d7b35d2593b4339af8ef0f407675e942e6a6fd Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:33:52 +0200 Subject: [PATCH 23/43] fix: Correct spelling mistakes in infiniband node and ip_device - substract(ion)/substracted -> subtract(ion)/subtracted - succesfully -> successfully - Unrealiable -> Unreliable - 'adress in hex' -> 'address in hex' Signed-off-by: Steffen Vogel --- common/lib/kernel/devices/ip_device.cpp | 2 +- include/villas/nodes/infiniband.hpp | 4 ++-- lib/nodes/infiniband.cpp | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/lib/kernel/devices/ip_device.cpp b/common/lib/kernel/devices/ip_device.cpp index af6612625..6a8c00009 100644 --- a/common/lib/kernel/devices/ip_device.cpp +++ b/common/lib/kernel/devices/ip_device.cpp @@ -19,7 +19,7 @@ using villas::kernel::devices::IpDevice; IpDevice IpDevice::from(const fs::path unsafe_path) { if (!is_path_valid(unsafe_path)) throw RuntimeError( - "Path {} failed validation as IpDevicePath [adress in hex].[name] ", + "Path {} failed validation as IpDevicePath [address in hex].[name] ", unsafe_path.string()); return IpDevice(unsafe_path); } diff --git a/include/villas/nodes/infiniband.hpp b/include/villas/nodes/infiniband.hpp index b21c76b44..4935c39fb 100644 --- a/include/villas/nodes/infiniband.hpp +++ b/include/villas/nodes/infiniband.hpp @@ -76,11 +76,11 @@ struct infiniband { // Counter to keep track of available recv. WRs unsigned available_recv_wrs; - /* Fixed number to substract from min. number available + /* Fixed number to subtract from min. number available * WRs in receive queue */ unsigned buffer_subtraction; - // Unrealiable connectionless data + // Unreliable connectionless data struct ud_s { ::rdma_ud_param ud; ::ibv_ah *ah; diff --git a/lib/nodes/infiniband.cpp b/lib/nodes/infiniband.cpp index 65f973a4f..c1ce59fef 100644 --- a/lib/nodes/infiniband.cpp +++ b/lib/nodes/infiniband.cpp @@ -320,14 +320,14 @@ int villas::node::ib_parse(NodeCompat *n, json_t *json) { int villas::node::ib_check(NodeCompat *n) { auto *ib = n->getData(); - // Check if read substraction makes sense + // Check if read subtraction makes sense if (ib->conn.buffer_subtraction < 2 * n->in.vectorize) throw RuntimeError( - "The buffer substraction value must be bigger than 2 * in.vectorize"); + "The buffer subtraction value must be bigger than 2 * in.vectorize"); if (ib->conn.buffer_subtraction >= ib->qp_init.cap.max_recv_wr - n->in.vectorize) - throw RuntimeError("The buffer substraction value cannot be bigger than " + throw RuntimeError("The buffer subtraction value cannot be bigger than " "in.max_wrs - in.vectorize"); // Check if the set value is a power of 2, and warn the user if this is not the case @@ -644,7 +644,7 @@ int villas::node::ib_start(NodeCompat *n) { } /* Several events should occur on the event channel, to make - * sure the nodes are succesfully connected. + * sure the nodes are successfully connected. */ n->logger->debug("Starting to monitor events on rdma_cm_id"); @@ -829,7 +829,7 @@ int villas::node::ib_read(NodeCompat *n, struct Sample *const smps[], throw RuntimeError("Was unable to post receive WR: {}, bad WR ID: {:#x}", ret, bad_wr->wr_id); - n->logger->debug("Succesfully posted receive Work Requests"); + n->logger->debug("Successfully posted receive Work Requests"); // Doesn't start if wcs == 0 for (int j = 0; j < wcs; j++) { @@ -844,9 +844,9 @@ int villas::node::ib_read(NodeCompat *n, struct Sample *const smps[], n->logger->warn("Work Completion status was not IBV_WC_SUCCESS: {}", (int)wc[j].status); - /* 32 byte of meta data is always transferred. We should substract it. + /* 32 byte of meta data is always transferred. We should subtract it. * Furthermore, in case of an unreliable connection, a 40 byte - * global routing header is transferred. This should be substracted as well. + * global routing header is transferred. This should be subtracted as well. */ int correction = (ib->conn.port_space == RDMA_PS_UDP) ? META_GRH_SIZE : META_SIZE; From d5e633d22c2899acb59d9cdfcfd63af304d79789 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:34:04 +0200 Subject: [PATCH 24/43] fix: Correct 'snd' -> 'and' in file header comments Signed-off-by: Steffen Vogel --- src/villas-hook.cpp | 2 +- src/villas-pipe.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/villas-hook.cpp b/src/villas-hook.cpp index 807e8577e..79e743036 100644 --- a/src/villas-hook.cpp +++ b/src/villas-hook.cpp @@ -1,4 +1,4 @@ -/* Receive messages from server snd print them on stdout. +/* Receive messages from server and print them on stdout. * * Author: Steffen Vogel * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University diff --git a/src/villas-pipe.cpp b/src/villas-pipe.cpp index 53a6477d9..ab4cb1f76 100644 --- a/src/villas-pipe.cpp +++ b/src/villas-pipe.cpp @@ -1,4 +1,4 @@ -/* Receive messages from server snd print them on stdout. +/* Receive messages from server and print them on stdout. * * Author: Steffen Vogel * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University From 348fd842cec189c66f3991d6d53fac3d91132f39 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:35:30 +0200 Subject: [PATCH 25/43] fix(tools): Correct spelling in integration-tests.sh output Signed-off-by: Steffen Vogel --- tools/integration-tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/integration-tests.sh b/tools/integration-tests.sh index d1d531f1f..b267a9459 100755 --- a/tools/integration-tests.sh +++ b/tools/integration-tests.sh @@ -59,7 +59,7 @@ export NUM_SAMPLES TESTS=${SRCDIR}/tests/integration/${FILTER}.sh -# Preperations +# Preparations mkdir -p ${LOGDIR} PASSED=0 @@ -105,7 +105,7 @@ for TEST in ${TESTS}; do SKIPPED=$((${SKIPPED} + 1)) ;; 124) - echo -e "\e[33m[TIME] \e[39m ${TESTNAME} (ran for more then ${TIMEOUT})" + echo -e "\e[33m[TIME] \e[39m ${TESTNAME} (ran for more than ${TIMEOUT})" TIMEDOUT=$((${TIMEDOUT} + 1)) FAILED=$((${FAILED} + 1)) ;; From 32b5af90ce65fa48ed7dd9cc57da9123af8b4216 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:35:57 +0200 Subject: [PATCH 26/43] fix: Remove duplicated 'the' in config example and OpenAPI descriptions Signed-off-by: Steffen Vogel --- doc/openapi/components/schemas/config/hooks/pmu_dft.yaml | 2 +- doc/openapi/components/schemas/config/path.yaml | 4 ++-- etc/examples/nodes/file.conf | 2 +- include/villas/node/config.hpp.in | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/openapi/components/schemas/config/hooks/pmu_dft.yaml b/doc/openapi/components/schemas/config/hooks/pmu_dft.yaml index 5ffb574f2..d79bcc8fd 100644 --- a/doc/openapi/components/schemas/config/hooks/pmu_dft.yaml +++ b/doc/openapi/components/schemas/config/hooks/pmu_dft.yaml @@ -84,7 +84,7 @@ allOf: - center - right default: center - description: The timestamp alignment in respect to the the window. + description: The timestamp alignment in respect to the window. phase_offset: type: number default: 0.0 diff --git a/doc/openapi/components/schemas/config/path.yaml b/doc/openapi/components/schemas/config/path.yaml index 783e17897..c57f9bb25 100644 --- a/doc/openapi/components/schemas/config/path.yaml +++ b/doc/openapi/components/schemas/config/path.yaml @@ -64,7 +64,7 @@ properties: mask: description: | - This setting allows masking the the input nodes which can trigger the path. + This setting allows masking the input nodes which can trigger the path. See also `mode` setting. @@ -107,7 +107,7 @@ properties: A boolean flag which enables the poll-based mode for reading samples from multiple path sources. **Note:** This is an advanced setting. - Most users should use the the default value which will always do the right thing based on the number and type of input nodes for this path. + Most users should use the default value which will always do the right thing based on the number and type of input nodes for this path. type: boolean diff --git a/etc/examples/nodes/file.conf b/etc/examples/nodes/file.conf index 6a5c2ab42..a68522371 100644 --- a/etc/examples/nodes/file.conf +++ b/etc/examples/nodes/file.conf @@ -5,7 +5,7 @@ nodes = { file_node = { type = "file" - # These options specify the URI where the the files are stored + # These options specify the URI where the files are stored # The URI accepts all format tokens of (see strftime(3)) uri = "logs/input.log" # uri = "logs/output_%F_%T.log" diff --git a/include/villas/node/config.hpp.in b/include/villas/node/config.hpp.in index 2ea3cb756..0fd3b4f5d 100644 --- a/include/villas/node/config.hpp.in +++ b/include/villas/node/config.hpp.in @@ -18,7 +18,7 @@ #define MAX_SAMPLE_LENGTH 512u #define DEFAULT_FORMAT_BUFFER_LENGTH 4096u -/* Number of hugepages which are requested from the the kernel. +/* Number of hugepages which are requested from the kernel. * @see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt */ #define DEFAULT_NR_HUGEPAGES 100 From 2c531ec8aa590d352ef30c6900b7e948f312751e Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 7 Aug 2026 23:50:45 +0200 Subject: [PATCH 27/43] fix(villas-pipe): Add missing closing quote in RuntimeError format string The string literal in the node-type start error path was missing its terminating quote and the closing parenthesis of the RuntimeError call, breaking compilation. Close the string and the call. Signed-off-by: Steffen Vogel --- src/villas-pipe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/villas-pipe.cpp b/src/villas-pipe.cpp index ab4cb1f76..ef293b32a 100644 --- a/src/villas-pipe.cpp +++ b/src/villas-pipe.cpp @@ -447,7 +447,7 @@ class Pipe : public Tool { ret = node->getFactory()->start(&sn); if (ret) - throw RuntimeError("Failed to initialize node type {}: reason={}, + throw RuntimeError("Failed to initialize node type {}: reason={}", node->getFactory()->getName(), ret); sn.startInterfaces(); From 26ba87d29236ef7a5b04b6afa24509ae39311eac Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 00:11:24 +0200 Subject: [PATCH 28/43] fix: Correct spelling in plugin descriptions and CLI help These strings surface in 'villas node -h' and the generated usage docs: - amqp: 'Protoocl' -> 'Protocol' - example: 'for staring' -> 'for starting' - temper: 'An temper for staring' -> 'A template for starting' - villas-test-config: 'plausability' -> 'plausibility' Signed-off-by: Steffen Vogel --- lib/nodes/amqp.cpp | 2 +- lib/nodes/example.cpp | 2 +- lib/nodes/temper.cpp | 2 +- src/villas-test-config.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/nodes/amqp.cpp b/lib/nodes/amqp.cpp index 07da7a5a6..4eb7df2d1 100644 --- a/lib/nodes/amqp.cpp +++ b/lib/nodes/amqp.cpp @@ -398,7 +398,7 @@ static NodeCompatType p; __attribute__((constructor(110))) static void register_plugin() { p.name = "amqp"; - p.description = "Advanced Message Queueing Protoocl (rabbitmq-c)"; + p.description = "Advanced Message Queueing Protocol (rabbitmq-c)"; p.vectorize = 0; p.size = sizeof(struct amqp); p.init = amqp_init; diff --git a/lib/nodes/example.cpp b/lib/nodes/example.cpp index 579d659e4..670c3b10d 100644 --- a/lib/nodes/example.cpp +++ b/lib/nodes/example.cpp @@ -165,7 +165,7 @@ class ExampleNode : public Node { // Register node static char n[] = "example"; -static char d[] = "An example for staring new node-type implementations"; +static char d[] = "An example for starting new node-type implementations"; static NodePlugin Date: Sat, 8 Aug 2026 00:48:04 +0200 Subject: [PATCH 29/43] fix(test_rtt): Correct inverted strcmp logic and max-mode in parseMode Two bugs in parseMode(): - strcmp() returns 0 on match, but the branches tested 'if (strcmp(...))' (truthy on mismatch), so the intended mode was never selected. - The 'max' branch returned Mode::MIN instead of Mode::MAX. Use '== 0' comparisons and return Mode::MAX for 'max'. Signed-off-by: Steffen Vogel --- lib/nodes/test_rtt.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/nodes/test_rtt.cpp b/lib/nodes/test_rtt.cpp index efa884330..2959ca6c1 100644 --- a/lib/nodes/test_rtt.cpp +++ b/lib/nodes/test_rtt.cpp @@ -116,17 +116,17 @@ int TestRTT::prepare() { } static enum TestRTT::Mode parseMode(const char *mode_str) { - if (strcmp(mode_str, "min")) + if (strcmp(mode_str, "min") == 0) return TestRTT::Mode::MIN; - else if (strcmp(mode_str, "max")) - return TestRTT::Mode::MIN; - else if (strcmp(mode_str, "stop_after_count")) + else if (strcmp(mode_str, "max") == 0) + return TestRTT::Mode::MAX; + else if (strcmp(mode_str, "stop_after_count") == 0) return TestRTT::Mode::STOP_COUNT; - else if (strcmp(mode_str, "stop_after_duration")) + else if (strcmp(mode_str, "stop_after_duration") == 0) return TestRTT::Mode::STOP_DURATION; - else if (strcmp(mode_str, "at_least_count")) + else if (strcmp(mode_str, "at_least_count") == 0) return TestRTT::Mode::AT_LEAST_COUNT; - else if (strcmp(mode_str, "at_least_duration")) + else if (strcmp(mode_str, "at_least_duration") == 0) return TestRTT::Mode::AT_LEAST_DURATION; else return TestRTT::Mode::UNKNOWN; From d76f084fafacd53cd33131881e2965b1e896522c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 00:48:31 +0200 Subject: [PATCH 30/43] fix(hooks): Read correctly-spelled start/end_frequency in pmu_dft The hook unpacked 'start_freqency'/'end_freqency' (missing the second 'u') while the OpenAPI schema and documentation use 'start_frequency'/ 'end_frequency', so documented configs were silently ignored. Read the correct keys and keep the misspelled ones as a backward-compatible alias. Signed-off-by: Steffen Vogel --- lib/hooks/pmu_dft.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/hooks/pmu_dft.cpp b/lib/hooks/pmu_dft.cpp index 37402e2cc..b307e49d2 100644 --- a/lib/hooks/pmu_dft.cpp +++ b/lib/hooks/pmu_dft.cpp @@ -253,8 +253,8 @@ class PmuDftHook : public MultiSignalHook { json, &err, 0, "{ s?: i, s?: F, s?: F, s?: F, s?: i, s?: i, s?: s, s?: s, s?: s, s?: " "i, s?: s, s?: b, s?: s, s?: F, s?: F, s?: F, s?: F}", - "sample_rate", &sampleRate, "start_freqency", &startFrequency, - "end_freqency", &endFreqency, "frequency_resolution", + "sample_rate", &sampleRate, "start_frequency", &startFrequency, + "end_frequency", &endFreqency, "frequency_resolution", &frequencyResolution, "dft_rate", &rate, "window_size_factor", &windowSizeFactor, "window_type", &windowTypeC, "padding_type", &paddingTypeC, "estimate_type", &estimateTypeC, "pps_index", &ppsIndex, @@ -265,6 +265,14 @@ class PmuDftHook : public MultiSignalHook { if (ret) throw ConfigError(json, err, "node-config-hook-dft"); + // Backward-compatibility: accept the previously misspelled keys. + json_t *json_start = json_object_get(json, "start_freqency"); + if (json_start) + startFrequency = json_number_value(json_start); + json_t *json_end = json_object_get(json, "end_freqency"); + if (json_end) + endFreqency = json_number_value(json_end); + windowSize = sampleRate * windowSizeFactor / (double)rate; logger->info( "Set windows size to {} samples which fits {} times the rate {}s", From 292afdfd548113fba57cdea48e51ea47da42f1f2 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 00:49:05 +0200 Subject: [PATCH 31/43] fix(villas-signal): Enable and document -p, -w, -L, -H options The option handlers for -w (pulse width), -L (pulse low) and -H (pulse high) existed but were unreachable because the getopt string lacked those letters. Add them, document -p (phase, already accepted) and the pulse options in usage(). Signed-off-by: Steffen Vogel --- src/villas-signal.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/villas-signal.cpp b/src/villas-signal.cpp index c5096bab5..1eeeb4b3d 100644 --- a/src/villas-signal.cpp +++ b/src/villas-signal.cpp @@ -80,6 +80,13 @@ class Signal : public Tool { << std::endl << " -o OFF the DC bias" << std::endl << " -l NUM only send LIMIT messages and stop" << std::endl + << " -p FLT the phase of the signal" << std::endl + << " -w FLT the pulse width (for 'square'/'pulse' signals)" + << std::endl + << " -L FLT the low level (for 'square'/'pulse' signals)" + << std::endl + << " -H FLT the high level (for 'square'/'pulse' signals)" + << std::endl << std::endl; printCopyright(); @@ -105,7 +112,7 @@ class Signal : public Tool { // Parse optional command line arguments int c; char *endptr; - while ((c = getopt(argc, argv, "v:r:F:f:l:a:D:no:d:hVp:")) != -1) { + while ((c = getopt(argc, argv, "v:r:F:f:l:a:D:no:d:hVp:w:L:H:")) != -1) { switch (c) { case 'n': rt = 0; From 04846d8bdc62d19ea54e2dee02b8b0577c7465ae Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 00:49:31 +0200 Subject: [PATCH 32/43] fix(villas-test-config): Parse advertised -d debug-level option usage() documented '-d LVL' but the getopt string 'hcVD' had no 'd:', so the flag was rejected. Add 'd:' and set the log level. Signed-off-by: Steffen Vogel --- src/villas-test-config.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/villas-test-config.cpp b/src/villas-test-config.cpp index 6330a9b19..c1933fb07 100644 --- a/src/villas-test-config.cpp +++ b/src/villas-test-config.cpp @@ -61,12 +61,16 @@ class TestConfig : public Tool { void parse() override { int c; - while ((c = getopt(argc, argv, "hcVD")) != -1) { + while ((c = getopt(argc, argv, "hcVDd:")) != -1) { switch (c) { case 'c': check = true; break; + case 'd': + Log::getInstance().setLevel(optarg); + break; + case 'D': dump = true; break; From 2d8041f9a29545370ecca843b378a136cea69f11 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 09:51:26 +0200 Subject: [PATCH 33/43] fix(openapi): Add enabled and correct port default in http schema The http schema omitted the 'enabled' boolean that lib/web.cpp parses under JSON_STRICT (so setting it raised a ConfigError), and declared a default port of 80 when the actual default is 8080 for unprivileged users (80 only as root). Signed-off-by: Steffen Vogel --- doc/openapi/components/schemas/config/http.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/openapi/components/schemas/config/http.yaml b/doc/openapi/components/schemas/config/http.yaml index f8ecfd215..44c896f2f 100644 --- a/doc/openapi/components/schemas/config/http.yaml +++ b/doc/openapi/components/schemas/config/http.yaml @@ -4,12 +4,20 @@ --- type: object properties: + enabled: + type: boolean + default: true + title: Enable HTTP/WebSocket server + description: | + Whether the HTTP & WebSocket server listens on a port. + port: type: integer - default: 80 + default: 8080 title: Listening port description: | - The TCP port number on which HTTP & WebSocket server. + The TCP port number on which the HTTP & WebSocket server listens. + Defaults to 80 when running as root, otherwise 8080. ssl_cert: type: string From 99541953a288f6b3ffef3056f79d52868a68f58c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 09:54:34 +0200 Subject: [PATCH 34/43] fix(openapi): Align zeromq and websocket schemas with parsed options - zeromq: add the 'pattern' option parsed by the code, and rename the curve key 'private_key' to the 'secret_key' the code actually reads. - websocket: add the 'wait_connected' boolean parsed by the code. Signed-off-by: Steffen Vogel --- .../components/schemas/config/nodes/websocket.yaml | 7 +++++++ .../components/schemas/config/nodes/zeromq.yaml | 13 +++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/doc/openapi/components/schemas/config/nodes/websocket.yaml b/doc/openapi/components/schemas/config/nodes/websocket.yaml index 236b1559e..1c74f92ad 100644 --- a/doc/openapi/components/schemas/config/nodes/websocket.yaml +++ b/doc/openapi/components/schemas/config/nodes/websocket.yaml @@ -29,5 +29,12 @@ allOf: format: uri description: A WebSocket URI + wait_connected: + type: boolean + default: true + description: | + Wait until all configured client connections in `destinations` are + established before finishing node startup. + - $ref: ../node_signals.yaml - $ref: ../node.yaml diff --git a/doc/openapi/components/schemas/config/nodes/zeromq.yaml b/doc/openapi/components/schemas/config/nodes/zeromq.yaml index f263689be..a0cf9add5 100644 --- a/doc/openapi/components/schemas/config/nodes/zeromq.yaml +++ b/doc/openapi/components/schemas/config/nodes/zeromq.yaml @@ -14,6 +14,15 @@ allOf: - pubsub - radiodish + pattern: + type: string + enum: + - pubsub + - radiodish + default: pubsub + description: | + The ZeroMQ socket pattern to use. + publish: type: string format: uri @@ -49,10 +58,10 @@ allOf: description: | The public key of the server. - private_key: + secret_key: type: string description: | - The private key of the server. + The secret (private) key of the server. out: type: object From 9045ffeb6836a25187c5b1e1d6cb7fc5d1e5d6ab Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 09:54:50 +0200 Subject: [PATCH 35/43] fix(examples): Correct spelling in redis and ngsi example comments - redis.conf: 'channel tp be used' -> 'channel to be used' - ngsi.conf: 'FIRWARE' -> 'FIWARE' Signed-off-by: Steffen Vogel --- etc/examples/nodes/ngsi.conf | 2 +- etc/examples/nodes/redis.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/examples/nodes/ngsi.conf b/etc/examples/nodes/ngsi.conf index ad367571c..edb85b52b 100644 --- a/etc/examples/nodes/ngsi.conf +++ b/etc/examples/nodes/ngsi.conf @@ -5,7 +5,7 @@ nodes = { ngsi_node = { type = "ngsi" - # The HTTP REST API endpoint of the FIRWARE context broker + # The HTTP REST API endpoint of the FIWARE context broker endpoint = "http://46.101.131.212:1026" # Add an 'Auth-Token' token header to each request diff --git a/etc/examples/nodes/redis.conf b/etc/examples/nodes/redis.conf index 2816de3cd..648a44737 100644 --- a/etc/examples/nodes/redis.conf +++ b/etc/examples/nodes/redis.conf @@ -12,7 +12,7 @@ nodes = { # The Redis key to be used for mode = 'key' or 'hash' (default is the node name) key = "my_key" - # The Redis channel tp be used for mode = 'channel' (default is the node name) + # The Redis channel to be used for mode = 'channel' (default is the node name) channel = "my_channel" # One of: From 75e0b8ebf574bdfa2dfb18e815265c58746c87c3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 09:57:14 +0200 Subject: [PATCH 36/43] fix(examples): Use correct 'samples' option in skip_first example comment The commented-out alternative referenced 'sequence', but the hook parses the 'samples' key. Signed-off-by: Steffen Vogel --- etc/examples/hooks/skip_first.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/examples/hooks/skip_first.conf b/etc/examples/hooks/skip_first.conf index 8df3549fe..55e6c33f1 100644 --- a/etc/examples/hooks/skip_first.conf +++ b/etc/examples/hooks/skip_first.conf @@ -13,7 +13,7 @@ paths = ( type = "skip_first" seconds = 10 - # sequence = 10 + # samples = 10 } ) } From 3d037ae1778b8d5215b2020d56936bdbac02df96 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 22:34:12 +0200 Subject: [PATCH 37/43] fix: Correct spelling typos in comments and log messages Fix 'managment' -> 'management', 'transfering' -> 'transferring', and 'occured' -> 'occurred'. Signed-off-by: Steffen Vogel --- common/lib/memory.cpp | 2 +- common/lib/memory_manager.cpp | 2 +- include/villas/nodes/comedi.hpp | 2 +- lib/nodes/infiniband.cpp | 4 ++-- python/villas/node/test_formats.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/lib/memory.cpp b/common/lib/memory.cpp index 9750194b3..a9f60d96b 100644 --- a/common/lib/memory.cpp +++ b/common/lib/memory.cpp @@ -1,4 +1,4 @@ -/* Memory managment. +/* Memory management. * * Author: Daniel Krebs * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University diff --git a/common/lib/memory_manager.cpp b/common/lib/memory_manager.cpp index 904b228b3..1ea8d6d25 100644 --- a/common/lib/memory_manager.cpp +++ b/common/lib/memory_manager.cpp @@ -1,4 +1,4 @@ -/* Memory managment. +/* Memory management. * * Author: Daniel Krebs * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University diff --git a/include/villas/nodes/comedi.hpp b/include/villas/nodes/comedi.hpp index 81881c5d8..c1e263d51 100644 --- a/include/villas/nodes/comedi.hpp +++ b/include/villas/nodes/comedi.hpp @@ -34,7 +34,7 @@ struct comedi_direction { int sample_rate_hz; // Sample rate in Hz bool present; // Config present bool enabled; // Card is started successfully - bool running; // Card is actively transfering samples + bool running; // Card is actively transferring samples struct timespec started; // Timestamp when sampling started struct timespec last_debug; // Timestamp of last debug output size_t counter; // Number of villas samples transfered diff --git a/lib/nodes/infiniband.cpp b/lib/nodes/infiniband.cpp index c1ce59fef..ab56d3af9 100644 --- a/lib/nodes/infiniband.cpp +++ b/lib/nodes/infiniband.cpp @@ -834,7 +834,7 @@ int villas::node::ib_read(NodeCompat *n, struct Sample *const smps[], // Doesn't start if wcs == 0 for (int j = 0; j < wcs; j++) { if (!((wc[j].opcode & IBV_WC_RECV) && wc[j].status == IBV_WC_SUCCESS)) { - // Drop all values, we don't know where the error occured + // Drop all values, we don't know where the error occurred read_values = 0; } @@ -967,7 +967,7 @@ int villas::node::ib_write(NodeCompat *n, struct Sample *const smps[], * and prepare them to be released */ n->logger->debug( - "Bad WR occured with ID: {:#x} and S/G address: {:p}: {}", + "Bad WR occurred with ID: {:#x} and S/G address: {:p}: {}", bad_wr->wr_id, (void *)bad_wr->sg_list, ret); while (1) { diff --git a/python/villas/node/test_formats.py b/python/villas/node/test_formats.py index 366281a24..b422f40fe 100644 --- a/python/villas/node/test_formats.py +++ b/python/villas/node/test_formats.py @@ -6,7 +6,7 @@ from cmath import sqrt -from villas.node.formats import SignalList, VillasHuman, Protobuf +from villas.node.formats import Protobuf, SignalList, VillasHuman from villas.node.sample import Sample, Timestamp From b5e984ec08db2ee858c5f7bf57a01722d63f354b Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 22:34:47 +0200 Subject: [PATCH 38/43] fix(api): Remove duplicated 'with' in UUID error messages Signed-off-by: Steffen Vogel --- lib/api/requests/node.cpp | 2 +- lib/api/requests/path.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/api/requests/node.cpp b/lib/api/requests/node.cpp index 89fab17f9..be1fd7e43 100644 --- a/lib/api/requests/node.cpp +++ b/lib/api/requests/node.cpp @@ -25,6 +25,6 @@ void NodeRequest::prepare() { node = nodes.lookup(uuid); if (!node) throw Error::badRequest(json_pack("{ s: s }", "uuid", matches[1].c_str()), - "No node found with with matching UUID"); + "No node found with matching UUID"); } } diff --git a/lib/api/requests/path.cpp b/lib/api/requests/path.cpp index b3ed3c5d1..91322f37c 100644 --- a/lib/api/requests/path.cpp +++ b/lib/api/requests/path.cpp @@ -23,5 +23,5 @@ void PathRequest::prepare() { path = paths.lookup(uuid); if (!path) throw Error::badRequest(json_pack("{ s: s }", "uuid", matches[1].c_str()), - "No path found with with matching UUID"); + "No path found with matching UUID"); } From b0f23026e5a3f6609d634ad4f622c0f1d22e3dfa Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 23:06:03 +0200 Subject: [PATCH 39/43] fix(hooks): Use correct ConfigError ID in moving-average hook The MovingAverageHook used the 'node-config-hook-rms' error ID (copy-paste from RMSHook). Use 'node-config-hook-ma' instead so configuration errors reference the correct documentation anchor. Signed-off-by: Steffen Vogel --- lib/hooks/ma.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hooks/ma.cpp b/lib/hooks/ma.cpp index fee09b7fc..1609d8929 100644 --- a/lib/hooks/ma.cpp +++ b/lib/hooks/ma.cpp @@ -57,7 +57,7 @@ class MovingAverageHook : public MultiSignalHook { ret = json_unpack_ex(json, &err, 0, "{ s?: i }", "window_size", &windowSize); if (ret) - throw ConfigError(json, err, "node-config-hook-rms"); + throw ConfigError(json, err, "node-config-hook-ma"); state = State::PARSED; } From 89de4be07c1ceadbf5cd40a1aa150273906f3bd4 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 23:06:33 +0200 Subject: [PATCH 40/43] fix(hooks): Initialize optional json_unpack outputs in digest hook The optional 'mode' and 'algorithm' keys were unpacked into uninitialized pointers. When absent, jansson leaves these pointers untouched, so the subsequent 'if (algorithm_str)' read an indeterminate pointer (undefined behavior). Initialize them to nullptr. Signed-off-by: Steffen Vogel --- lib/hooks/digest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/hooks/digest.cpp b/lib/hooks/digest.cpp index 4b81ae0c8..59295a7c8 100644 --- a/lib/hooks/digest.cpp +++ b/lib/hooks/digest.cpp @@ -193,8 +193,8 @@ class DigestHook : public Hook { Hook::parse(json); char const *uri_str; - char const *mode_str; - char const *algorithm_str; + char const *mode_str = nullptr; + char const *algorithm_str = nullptr; json_error_t err; int ret = From b23b4ed41db21c60e96850266a6bde236dd212e3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 8 Aug 2026 23:06:33 +0200 Subject: [PATCH 41/43] fix(hooks): Initialize optional 'mode' output in gate hook The optional 'mode' key was unpacked into an uninitialized pointer. When absent, jansson leaves the pointer untouched, so the subsequent 'if (mode_str)' read an indeterminate pointer (undefined behavior). Initialize it to nullptr. Signed-off-by: Steffen Vogel --- lib/hooks/gate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hooks/gate.cpp b/lib/hooks/gate.cpp index 265eac9ab..194b603a5 100644 --- a/lib/hooks/gate.cpp +++ b/lib/hooks/gate.cpp @@ -43,7 +43,7 @@ class GateHook : public SingleSignalHook { json_error_t err; - const char *mode_str; + const char *mode_str = nullptr; assert(state != State::STARTED); From 68170621cf966ddfa05acd1b17900ba2c9fbe747 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 9 Aug 2026 14:23:46 +0200 Subject: [PATCH 42/43] fix(pre-commit): Update black-pre-commit-mirror to version 24.10.0 Signed-off-by: Steffen Vogel --- .pre-commit-config.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e5327e624..4b5e9272d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -47,18 +47,18 @@ repos: - id: editorconfig-checker alias: ec args: - - -disable-indent-size - - -exclude - - ^LICENSE$|^LICENSES/|\.ecf$ + - -disable-indent-size + - -exclude + - ^LICENSE$|^LICENSES/|\.ecf$ # Using this mirror lets us use mypyc-compiled black, which is about 2x faster - repo: https://github.com/psf/black-pre-commit-mirror - rev: "23.3.0" + rev: "24.10.0" hooks: - id: black-jupyter exclude: .*_pb2.pyi?$ args: - - --line-length=90 + - --line-length=90 - repo: https://github.com/pycqa/flake8 rev: "7.3.0" @@ -66,7 +66,7 @@ repos: - id: flake8 exclude: .*_pb2.pyi?$ args: - - --max-line-length=90 + - --max-line-length=90 - repo: https://github.com/markdownlint/markdownlint rev: "v0.13.0" From 82224f21426c1f5a8764ce49da290cd5d71a0d5d Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 9 Aug 2026 14:24:24 +0200 Subject: [PATCH 43/43] fix(style): Fix code formatting with clang-format Signed-off-by: Steffen Vogel --- lib/api/requests/capabilities.cpp | 3 +-- lib/kernel/if.cpp | 10 ++++------ lib/nodes/file.cpp | 11 +++++------ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/api/requests/capabilities.cpp b/lib/api/requests/capabilities.cpp index 211e1c9be..2d47f7780 100644 --- a/lib/api/requests/capabilities.cpp +++ b/lib/api/requests/capabilities.cpp @@ -35,8 +35,7 @@ class CapabilitiesRequest : public Request { // Register API request static char n[] = "capabilities"; static char r[] = "/capabilities"; -static char d[] = - "get capabilities and details about this VILLASnode instance"; +static char d[] = "get capabilities and details about this VILLASnode instance"; static RequestPlugin p; } // namespace api diff --git a/lib/kernel/if.cpp b/lib/kernel/if.cpp index 8f7e6ceb9..bf83dd472 100644 --- a/lib/kernel/if.cpp +++ b/lib/kernel/if.cpp @@ -182,18 +182,16 @@ int Interface::setAffinity(int affinity) { file = fopen(filename.c_str(), "w"); if (file) { if (fprintf(file, "%8lx", (unsigned long)cset_pin) < 0) - throw SystemError( - "Failed to set affinity for IRQ {} on interface '{}'", irq, - getName()); + throw SystemError("Failed to set affinity for IRQ {} on interface '{}'", + irq, getName()); fclose(file); logger->debug("Set affinity of IRQ {} to {} {}", irq, cset_pin.count() == 1 ? "core" : "cores", (std::string)cset_pin); } else - throw SystemError( - "Failed to set affinity for IRQ {} on interface '{}'", irq, - getName()); + throw SystemError("Failed to set affinity for IRQ {} on interface '{}'", + irq, getName()); } return 0; diff --git a/lib/nodes/file.cpp b/lib/nodes/file.cpp index a5cd365b7..391cea1d1 100644 --- a/lib/nodes/file.cpp +++ b/lib/nodes/file.cpp @@ -181,12 +181,11 @@ char *villas::node::file_print(NodeCompat *n) { break; } - strcatf( - &buf, - "uri=%s, out.flush=%s, in.skip=%d, in.eof=%s, in.epoch=%s, " - "in.epoch_value=%.2f", - f->uri ? f->uri : f->uri_tmpl, f->flush ? "yes" : "no", f->skip_lines, - eof_str, epoch_str, time_to_double(&f->epoch)); + strcatf(&buf, + "uri=%s, out.flush=%s, in.skip=%d, in.eof=%s, in.epoch=%s, " + "in.epoch_value=%.2f", + f->uri ? f->uri : f->uri_tmpl, f->flush ? "yes" : "no", f->skip_lines, + eof_str, epoch_str, time_to_double(&f->epoch)); if (f->rate) strcatf(&buf, ", in.rate=%.1f", f->rate);