Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ build:nix:
--print-build-logs
".#villas-node-${SYSTEM}"

build:openapi:
stage: build
needs: []
image: node:24-alpine
script:
- npx -y @redocly/cli build-docs doc/openapi/openapi.yaml --output openapi.html
artifacts:
paths:
- openapi.html

# Stage: test

test:pre-commit:
Expand Down
13 changes: 12 additions & 1 deletion common/include/villas/timing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#pragma once

#include <cstdint>
#include <chrono>
#include <cstdio>
#include <ctime>

Expand All @@ -33,3 +33,14 @@ double time_to_double(const struct timespec *ts);

// Convert double containing seconds after 1970 to timespec.
struct timespec time_from_double(double secs);

// Convert timespec to an std::chrono::time_point.
template <typename Duration = std::chrono::nanoseconds>
std::chrono::time_point<std::chrono::system_clock, Duration>
time_to_timepoint(const struct timespec *ts) {
auto dur =
std::chrono::seconds(ts->tv_sec) + std::chrono::nanoseconds(ts->tv_nsec);

return std::chrono::time_point<std::chrono::system_clock, Duration>(
std::chrono::duration_cast<Duration>(dur));
}
3 changes: 3 additions & 0 deletions common/lib/tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ int Tool::run() {
try {
int ret;

// Setup environment
std::setlocale(LC_ALL, "en_US.UTF-8");

logger->info("This is VILLASnode {} (built on {}, {})",
CLR_BLD(CLR_YEL(PROJECT_VERSION)), CLR_BLD(CLR_MAG(__DATE__)),
CLR_BLD(CLR_MAG(__TIME__)));
Expand Down
21 changes: 21 additions & 0 deletions doc/openapi/components/schemas/config/duration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# yaml-language-server: $schema=http://json-schema.org/draft-07/schema
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
# SPDX-License-Identifier: Apache-2.0
---
oneOf:
- type: string
description: |
Duration as a string, e.g., "1h30m", "45s", "200ms".
pattern: (\d+d)?(\d+h)?(\d+m)?(\d+s)?(\d+ms)?(\d+us)?(\d+ns)?
examples:
- "6d23h30m50s40ms"
- "45s"
- "2d200ms"
- type: integer
description: |
Duration as integer.
minimum: 0
examples:
- 5400000
- 45000
- 200
20 changes: 3 additions & 17 deletions doc/openapi/components/schemas/config/hooks/frame.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,14 @@ allOf:
trigger:
description: The trigger for new frames.
type: string
default: sequence
default: timestamp
enum:
- sequence
- timestamp

unit:
description: The type of a timestamp trigger.
type: string
enum:
- milliseconds
- seconds
- minutes
- hours

interval:
description: The interval in which frames are annotated.
type: number
default: 1

offset:
description: An offset in the interval for the annotation of new frames.
type: number
default: 0
default: "1s"
$ref: ../../duration.yaml

- $ref: ../hook.yaml
9 changes: 8 additions & 1 deletion etc/examples/hooks/digest.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ paths = (

hooks = (
# Use a frame hook to generate NEW_FRAME annotations
"frame",
{
type = "frame"

# The interval at which frames & digests are generated
interval = "1s"
},
{
type = "digest"

# The algorithm used for digest calculation
algorithm = "sha256"

# The output file for digests
uri = "sequence.digest"
}
Expand Down
3 changes: 1 addition & 2 deletions etc/examples/hooks/frame.conf
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ paths = (
type = "frame"

trigger = "timestamp"
unit = "seconds"
interval = 10
interval = "3s"
}
)
}
Expand Down
96 changes: 96 additions & 0 deletions include/villas/config_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@

#pragma once

#include <chrono>
#include <regex>
#include <stdexcept>

#include <jansson.h>

#include <villas/node/config.hpp>
#include <villas/sample.hpp>

#include "villas/exceptions.hpp"

#ifdef WITH_CONFIG
#include <libconfig.h>
#endif
Expand Down Expand Up @@ -42,5 +48,95 @@ int json_object_extend(json_t *orig, json_t *merge);

json_t *json_load_cli(int argc, const char *argv[]);

template <typename Duration = std::chrono::nanoseconds>
Duration parse_duration(std::string_view input) {
using namespace std::literals::chrono_literals;

// Map unit strings to their corresponding chrono durations
static const std::unordered_map<std::string, std::chrono::nanoseconds>
unit_map = {
{"d", 24h}, // days
{"h", 1h}, // hours
{"m", 1min}, // minutes
{"s", 1s}, // seconds
{"ms", 1ms}, // milliseconds
{"us", 1us}, // microseconds
{"ns", 1ns} // nanoseconds
};

std::regex token_re(R"((\d+)([a-z]+))");
auto begin = std::regex_iterator(input.begin(), input.end(), token_re);
auto end = std::regex_iterator<std::string_view::const_iterator>();

std::chrono::nanoseconds total_duration{0};

for (auto match = begin; match != end; ++match) {
if (match->size() != 3) {
throw RuntimeError("Invalid duration format: {}", match->str());
}

auto number_str = match->str(1);
auto unit_str = match->str(2);

auto it = unit_map.find(unit_str);
if (it == unit_map.end()) {
throw RuntimeError("Unknown duration unit: {}", unit_str);
}

auto unit = it->second;

int64_t number;
try {
number = std::stoul(number_str);
} catch (const std::invalid_argument &e) {
throw RuntimeError("Invalid number in duration: {}", match->str());
} catch (const std::out_of_range &e) {
throw RuntimeError("Duration overflows maximum representable value: {}",
match->str());
}

auto duration = unit * number;

if (duration > Duration::zero() && duration < Duration(1))
throw RuntimeError("Duration underflows minimum representable value");

if (unit.count() != 0 &&
duration.count() / unit.count() != number) // Check for overflow.
throw RuntimeError("Duration overflows maximum representable value: {}",
match->str());

total_duration += duration;
}

return std::chrono::duration_cast<Duration>(total_duration);
}

template <typename Duration = std::chrono::nanoseconds>
Duration parse_duration(json_t *json) {
switch (json_typeof(json)) {
case JSON_INTEGER: {
int64_t value = json_integer_value(json);
if (value < 0) {
throw ConfigError(json, "duration-negative", "Negative duration value");
}

return Duration(value);
}

case JSON_STRING: {
try {
return parse_duration<Duration>(
std::string_view(json_string_value(json), json_string_length(json)));
} catch (const RuntimeError &e) {
throw ConfigError(json, "duration", "{}", e.what());
}
}

default:
throw ConfigError(json, "duration",
"Expected a string or integer for duration");
}
}

} // namespace node
} // namespace villas
9 changes: 6 additions & 3 deletions include/villas/sample.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <memory>

#include <villas/log.hpp>
#include <villas/signal.hpp>
Expand Down Expand Up @@ -54,7 +55,12 @@ enum class SampleFlags {
ALL = -1
};

// Decrease reference count and release memory if last reference was held.
int sample_decref(struct Sample *s);

struct Sample {
using PtrUnique = std::unique_ptr<Sample, decltype(&sample_decref)>;

uint64_t sequence; // The sequence number of this sample.
unsigned length; // The number of values in sample::values which are valid.
unsigned
Expand Down Expand Up @@ -115,9 +121,6 @@ void sample_free_many(struct Sample *smps[], int cnt);
// Increase reference count of sample
int sample_incref(struct Sample *s);

// Decrease reference count and release memory if last reference was held.
int sample_decref(struct Sample *s);

int sample_copy(struct Sample *dst, const struct Sample *src);

// Dump all details about a sample to debug log
Expand Down
1 change: 0 additions & 1 deletion include/villas/signal_list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

#pragma once

#include <list>
#include <memory>

#include <jansson.h>
Expand Down
Loading