Skip to content
Open
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
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ find_package(Criterion)
find_package(OpalOrchestra)
find_package(LibXml2)
find_package(OpalAsyncApi)
find_package(FMI)

# Check for tools
find_program(PROTOBUFC_COMPILER NAMES protoc-c)
Expand Down Expand Up @@ -199,6 +200,7 @@ cmake_dependent_option(WITH_NODE_ETHERCAT "Build with ethercat node-type"
cmake_dependent_option(WITH_NODE_EXAMPLE "Build with example node-type" "${WITH_DEFAULTS}" "" OFF)
cmake_dependent_option(WITH_NODE_EXEC "Build with exec node-type" "${WITH_DEFAULTS}" "" OFF)
cmake_dependent_option(WITH_NODE_FILE "Build with file node-type" "${WITH_DEFAULTS}" "" OFF)
cmake_dependent_option(WITH_NODE_FMU "Build with fmu node-type" "${WITH_DEFAULTS}" "FMI_FOUND" OFF)
cmake_dependent_option(WITH_NODE_FPGA "Build with fpga node-type" "${WITH_DEFAULTS}" "WITH_FPGA" OFF)
cmake_dependent_option(WITH_NODE_IEC60870 "Build with iec60870 node-types" "${WITH_DEFAULTS}" "LIB60870_FOUND; NOT WITHOUT_GPL" OFF)
cmake_dependent_option(WITH_NODE_IEC61850 "Build with iec61850 node-types" "${WITH_DEFAULTS}" "LIBIEC61850_FOUND; NOT WITHOUT_GPL" OFF)
Expand Down Expand Up @@ -309,6 +311,7 @@ add_feature_info(NODE_ETHERCAT WITH_NODE_ETHERCAT "Build with
add_feature_info(NODE_EXAMPLE WITH_NODE_EXAMPLE "Build with example node-type")
add_feature_info(NODE_EXEC WITH_NODE_EXEC "Build with exec node-type")
add_feature_info(NODE_FILE WITH_NODE_FILE "Build with file node-type")
add_feature_info(NODE_FMU WITH_NODE_FMU "Build with fmu node-type")
add_feature_info(NODE_FPGA WITH_NODE_FPGA "Build with fpga node-type")
add_feature_info(NODE_IEC60870 WITH_NODE_IEC60870 "Build with iec60870 node-types")
add_feature_info(NODE_IEC61850 WITH_NODE_IEC61850 "Build with iec61850 node-types")
Expand Down
26 changes: 26 additions & 0 deletions cmake/FindFMI.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# CMakeLists.txt.
#
# Author: Ritesh Karki
# SPDX-FileCopyrightText: 2014-2026 Institute for Automation of Complex Power Systems, RWTH Aachen University
# SPDX-License-Identifier: Apache-2.0

find_path(FMI_INCLUDE_DIR
NAMES fmilib.h
)

find_library(FMI_LIBRARY fmilib
PATHS /usr/local/lib /usr/local/lib64
)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FMI DEFAULT_MSG FMI_LIBRARY FMI_INCLUDE_DIR)

mark_as_advanced(FMI_INCLUDE_DIR FMI_LIBRARY)

if(FMI_FOUND)
add_library(FMI SHARED IMPORTED)
set_target_properties(FMI PROPERTIES
IMPORTED_LOCATION "${FMI_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${FMI_INCLUDE_DIR}"
)
endif()
1 change: 1 addition & 0 deletions doc/openapi/components/schemas/config/node_obj.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ discriminator:
example: nodes/_example.yaml
exec: nodes/_exec.yaml
file: nodes/_file.yaml
fmu: nodes/_fmu.yaml
fpga: nodes/_fpga.yaml
iec60870-5-104: nodes/_iec60870-5-104.yaml
iec61850-8-1: nodes/_iec61850-8-1.yaml
Expand Down
7 changes: 7 additions & 0 deletions doc/openapi/components/schemas/config/nodes/_fmu.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# 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
---
allOf:
- $ref: ../node_obj.yaml
- $ref: file.yaml
71 changes: 71 additions & 0 deletions doc/openapi/components/schemas/config/nodes/fmu.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# yaml-language-server: $schema=http://json-schema.org/draft-07/schema
# SPDX-FileCopyrightText: 2014-2026 Institute for Automation of Complex Power Systems, RWTH Aachen University
# SPDX-License-Identifier: Apache-2.0
---
allOf:
- type: object
properties:
fmu_path:
format: uri
description: |
Specifies the URI to a FMU model

fmu_unpack_path:
format: uri
description: |
Specifies the URI to a directory which has the unpacked files of the FMU model (mainly the shared library and the modelDescription.xml for the model)

fmuWritefirst:
type: boolean
description: |
Specifies whether the model has to be writtem with input values before running. `true` denotes that the model should use the input values. `false` would make the model use default values instead.

startTime:
type: number
description: |
Specifies the start time for the simulation. Value has to be at least one `stepSize` lesser than `stopTime`.

stopTime:
type: number
description: |
Specifies the stop time for the simulation. The number of steps is calculated then by the difference between `startTime` and `stopTime` divided by the `stepSize`.

stepSize:
type: number
description: |
Specifies the stepSize for the simulation. Special care has to be taken to ensure that the value is equal to the value mantioned in modelDescription.xml.

in:
type: object
properties:
signals:
type: array
description: |
The input signals for the model have to be mentioned here as elements of an array while specifying the name (should be the same as that found in the modelDescription file) and the datatype.

**Example**:

```
signals = (
{name = "In1", type = "float"},
{name = "In2", type = "int"}
)
```
out:
type: object
properties:
signals:
type: array
description: |
The output signals for the model have to be mentioned here as elements of an array while specifying the name (should be the same as that found in the modelDescription file) and the datatype.

**Example**:

```
signals = (
{name = "Out1", type = "float"}
)
```

- $ref: ../node_signals.yaml
- $ref: ../node.yaml
61 changes: 61 additions & 0 deletions etc/examples/nodes/fmu.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
# SPDX-License-Identifier: Apache-2.0

nodes = {
file_output = {
type = "file"
# format = "csv"
uri = "/workspaces/node/fmu_temp/output.dat"
out = {

}
},

signal_node = {
type = "signal.v2"
rate = 100.0
realtime = true

limit = 100

in = {
signals = (
{ name = "sine1", signal = "sine", amplitude = 1, frequency = 100 },
# { name = "in2", signal = "constant", amplitude = 1 },
)
}
},
fmu_node = {
type = "fmu"
# Path to fmu file
fmu_path = "/workspaces/node/fmu_temp/asine.fmu"
fmu_unpack_path = "/workspaces/node/fmu_temp/fmu_asine"
fmu_writefirst = true
stopTime = 10.0
startTime = 0.0
stepSize = 0.2

in = {
signals = (
{name = "In1", type = "float"}
)
}

out = {
signals = (
{name = "Out1", type = "float"},
)
}
}
}

paths = (
{
in = "signal_node",
out = "fmu_node"
},
{
in = "fmu_node",
out = "file_output"
},
)
76 changes: 76 additions & 0 deletions include/villas/nodes/fmu.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* Node type: Functional Mock-up unit.
*
* Author: Ritesh Karki <ritesh.karki@rwth-aachen.de>, Jitpanu Maneeratpongsuk <jitpanu.maneeratpongsuk@rwth-aachen.de>
* SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, RWTH Aachen University
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once

#include <string>
#include <vector>

#include <fmilib.h>

#include <villas/format.hpp>
#include <villas/node.hpp>

namespace villas {
namespace node {

// Forward declarations
struct Sample;

class FmuNode : public Node {
protected:
int parse(json_t *json) override;

int _read(struct Sample *smps[], unsigned cnt) override;
int _write(struct Sample *smps[], unsigned cnt) override;

bool writingTurn = true;
const char *path;
const char *unpack_path;

timespec ts;
pthread_mutex_t mutex;
pthread_cond_t cv;

fmi3_import_t *fmu;
jm_callbacks callbacks;
fmi_import_context_t *context;

public:
FmuNode(const uuid_t &id = {}, const std::string &name = "");
struct fmu_signal {
unsigned int ref = 0;
fmi3_base_type_enu_t type = fmi3_base_type_enu_t::fmi3_base_type_float64;
std::string name;
};

std::vector<fmu_signal> signalIn;
std::vector<fmu_signal> signalOut;

int prepare() override;

int check() override;

int start() override;

int stop() override;

// ~FmuNode();

private:
void parse_signal(json_t *json, bool in);
double currentTime = 0;
double stepSize = 0.1;
double stopTime = 0;
double startTime = 0;
bool stopTimeDef = false;
double nextTime = 0.0;
void get_vr(const char *var_name, fmi3_value_reference_t &ref,
fmi3_base_type_enu_t &type);
};

} // namespace node
} // namespace villas
6 changes: 6 additions & 0 deletions lib/nodes/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ if(WITH_NODE_WEBRTC)
list(APPEND LIBRARIES LibDataChannel::LibDataChannel)
endif()

# Enable FMU node-type support
if(WITH_NODE_FMU)
list(APPEND NODE_SRC fmu.cpp)
list(APPEND LIBRARIES FMI)
endif()

add_library(nodes STATIC ${NODE_SRC})
target_include_directories(nodes PUBLIC ${INCLUDE_DIRS})
target_link_libraries(nodes PUBLIC ${LIBRARIES})
Loading
Loading