Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tweaks and fixes for running DPsim on an OPAL-RT real-time target #277

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class InterfaceWorkerVillas : public InterfaceWorker,

public:
using Ptr = std::shared_ptr<InterfaceWorkerVillas>;
using Sample = struct node::Sample;
using Sample = node::Sample;

static UInt villasPriority;
static UInt villasAffinity;
Expand Down
95 changes: 47 additions & 48 deletions dpsim-villas/src/InterfaceWorkerVillas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
#include <spdlog/sinks/stdout_color_sinks.h>

#include <dpsim-models/Logger.h>
#include <dpsim-villas/InterfaceWorkerVillas.h>
#include <villas/path.hpp>
#include <villas/signal_list.hpp>
// #include <villas/path.hpp>

using namespace CPS;
using namespace DPsim;
Expand All @@ -31,10 +30,10 @@ InterfaceWorkerVillas::InterfaceWorkerVillas(const String &nodeConfig,
mSampleLength(sampleLength) {}

void InterfaceWorkerVillas::open() {
SPDLOG_LOGGER_INFO(mLog, "Opening InterfaceWorkerVillas...");
SPDLOG_LOGGER_INFO(mLog, "Opening VILLASnode interface worker.");

if (!InterfaceWorkerVillas::villasInitialized) {
SPDLOG_LOGGER_INFO(mLog, "Initializing Villas...");
SPDLOG_LOGGER_INFO(mLog, "Initializing VILLASnode.");
initVillas();
InterfaceWorkerVillas::villasInitialized = true;
}
Expand All @@ -58,24 +57,24 @@ void InterfaceWorkerVillas::open() {
ret = mNode->parse(config);
if (ret < 0) {
SPDLOG_LOGGER_ERROR(mLog,
"Error: Node in InterfaceVillas failed to parse "
"Error: Node in VILLASnode interface failed to parse "
"config. Parse returned code {}",
ret);
std::exit(1);
}
ret = mNode->check();
if (ret < 0) {
SPDLOG_LOGGER_ERROR(
mLog,
"Error: Node in InterfaceVillas failed check. Check returned code {}",
ret);
SPDLOG_LOGGER_ERROR(mLog,
"Error: Node in VILLASnode interface failed check. "
"Check returned code {}",
ret);
std::exit(1);
}

SPDLOG_LOGGER_INFO(mLog, "Preparing VILLASNode instance...");
SPDLOG_LOGGER_INFO(mLog, "Preparing VILLASnode node instance.");
setupNodeSignals();
prepareNode();
SPDLOG_LOGGER_INFO(mLog, "Node is ready to send / receive data!");
SPDLOG_LOGGER_INFO(mLog, "VILLASnode node is ready to send / receive data!");
mOpened = true;

mSequence = 0;
Expand All @@ -93,40 +92,40 @@ void InterfaceWorkerVillas::prepareNode() {
sizeof(Sample) + SAMPLE_DATA_LENGTH(mSampleLength));
if (ret < 0) {
SPDLOG_LOGGER_ERROR(mLog,
"Error: InterfaceVillas failed to init sample pool. "
"pool_init returned code {}",
"Error: VILLASnode interface failed to init sample "
"pool. pool_init returned code {}",
ret);
std::exit(1);
}

ret = mNode->prepare();
if (ret < 0) {
SPDLOG_LOGGER_ERROR(mLog,
"Error: Node in InterfaceVillas failed to prepare. "
"Prepare returned code {}",
"Error: Node in VILLASnode interface failed to "
"prepare. Prepare returned code {}",
ret);
std::exit(1);
}

mNode->getFactory()->start(
nullptr); //We have no SuperNode, so just hope type_start doesnt use it...
nullptr); // We have no SuperNode, so just hope type_start doesnt use it...

ret = mNode->start();
if (ret < 0) {
SPDLOG_LOGGER_ERROR(mLog,
"Fatal error: failed to start node in InterfaceVillas. "
"Start returned code {}",
"Fatal error: failed to start node in VILLASnode "
"interface. Start returned code {}",
ret);
close();
std::exit(1);
}
}

void InterfaceWorkerVillas::setupNodeSignals() {
mNode->out.path = new node::Path();
mNode->out.path->signals = std::make_shared<node::SignalList>();
node::SignalList::Ptr nodeOutputSignals =
mNode->out.path->getOutputSignals(false);
// mNode->out.path = new node::Path();
// mNode->out.path->signals = std::make_shared<node::SignalList>();
// node::SignalList::Ptr nodeOutputSignals = mNode->out.path->getOutputSignals(false);
node::SignalList::Ptr nodeOutputSignals = mNode->out.signals;
nodeOutputSignals->clear();
int idx = 0;
for (const auto &[id, signal] : mExportSignals) {
Expand Down Expand Up @@ -154,21 +153,21 @@ void InterfaceWorkerVillas::setupNodeSignals() {
}

void InterfaceWorkerVillas::close() {
SPDLOG_LOGGER_INFO(mLog, "Closing InterfaceVillas...");
SPDLOG_LOGGER_INFO(mLog, "Closing VILLASnode interface.");
int ret = mNode->stop();
if (ret < 0) {
SPDLOG_LOGGER_ERROR(
mLog,
"Error: failed to stop node in InterfaceVillas. Stop returned code {}",
ret);
SPDLOG_LOGGER_ERROR(mLog,
"Error: failed to stop node in VILLASnode interface. "
"Stop returned code {}",
ret);
std::exit(1);
}
mOpened = false;
ret = node::pool_destroy(&mSamplePool);
if (ret < 0) {
SPDLOG_LOGGER_ERROR(mLog,
"Error: failed to destroy SamplePool in "
"InterfaceVillas. pool_destroy returned code {}",
"Error: failed to destroy SamplePool in VILLASnode "
"interface. pool_destroy returned code {}",
ret);
std::exit(1);
}
Expand Down Expand Up @@ -198,7 +197,7 @@ void InterfaceWorkerVillas::readValuesFromEnv(
if (ret < 0) {
SPDLOG_LOGGER_ERROR(mLog,
"Fatal error: failed to read sample from "
"InterfaceVillas. Poll returned code {}",
"VILLASnode interface. Poll returned code {}",
ret);
close();
std::exit(1);
Expand All @@ -215,7 +214,7 @@ void InterfaceWorkerVillas::readValuesFromEnv(
}
}
} else {
//If the node does not support pollFds just do a blocking read
// If the node does not support pollFds just do a blocking read
shouldRead = true;
}

Expand All @@ -226,7 +225,7 @@ void InterfaceWorkerVillas::readValuesFromEnv(
if (ret < 0) {
SPDLOG_LOGGER_ERROR(mLog,
"Fatal error: failed to read sample from "
"InterfaceVillas. Read returned code {}",
"VILLASnode interface. Read returned code {}",
ret);
close();
std::exit(1);
Expand All @@ -244,8 +243,8 @@ void InterfaceWorkerVillas::readValuesFromEnv(
}

if (!pollFds.empty()) {
//Manually clear the event file descriptor since Villas does not do that for some reason
//See https://github.com/VILLASframework/node/issues/309
// Manually clear the event file descriptor since VILLASnode does not do that for some reason
// See https://github.com/VILLASframework/node/issues/309
uint64_t result = 0;
ret = (int)::read(pollFds[0], &result, 8);
if (ret < 0) {
Expand Down Expand Up @@ -278,14 +277,14 @@ void InterfaceWorkerVillas::readValuesFromEnv(

void InterfaceWorkerVillas::writeValuesToEnv(
std::vector<Interface::AttributePacket> &updatedAttrs) {
//Update export sequence IDs
// Update export sequence IDs
for (const auto &packet : updatedAttrs) {
if (std::get<1>(mExports[packet.attributeId]) < packet.sequenceId) {
std::get<1>(mExports[packet.attributeId]) = packet.sequenceId;
}
}

//Remove outdated packets
// Remove outdated packets
auto beginOutdated = std::remove_if(
updatedAttrs.begin(), updatedAttrs.end(), [this](auto packet) {
return std::get<1>(mExports[packet.attributeId]) > packet.sequenceId;
Expand All @@ -299,17 +298,17 @@ void InterfaceWorkerVillas::writeValuesToEnv(
try {
sample = node::sample_alloc(&mSamplePool);
if (sample == nullptr) {
SPDLOG_LOGGER_ERROR(mLog, "InterfaceVillas could not allocate a new "
SPDLOG_LOGGER_ERROR(mLog, "VILLASnode interface could not allocate a new "
"sample! Not sending any data!");
return;
}

sample->signals = mNode->getOutputSignals(false);
sample->signals = mNode->out.signals;
auto beginExported = std::remove_if(
updatedAttrs.begin(), updatedAttrs.end(),
[this, &sampleFilled, &sample](auto packet) {
if (!std::get<2>(mExports[packet.attributeId])) {
//Write attribute to sample ASAP
// Write attribute to sample ASAP
std::get<0>(mExports[packet.attributeId])(packet.value, sample);
sampleFilled = true;
return true;
Expand All @@ -318,7 +317,7 @@ void InterfaceWorkerVillas::writeValuesToEnv(
});
updatedAttrs.erase(beginExported, updatedAttrs.end());

//Check if the remaining packets form a complete set
// Check if the remaining packets form a complete set
if (((long)updatedAttrs.size()) ==
std::count_if(mExports.cbegin(), mExports.cend(),
[this](auto x) { return std::get<2>(x); })) {
Expand All @@ -342,8 +341,8 @@ void InterfaceWorkerVillas::writeValuesToEnv(
} while (ret == 0);
if (ret < 0)
SPDLOG_LOGGER_ERROR(mLog,
"Failed to write samples to InterfaceVillas. Write "
"returned code {}",
"Failed to write samples to VILLASnode interface. "
"Write returned code {}",
ret);

sample_copy(mLastSample, sample);
Expand All @@ -363,10 +362,10 @@ void InterfaceWorkerVillas::writeValuesToEnv(
sample_decref(sample);

if (ret < 0)
SPDLOG_LOGGER_ERROR(
mLog,
"Failed to write samples to InterfaceVillas. Write returned code {}",
ret);
SPDLOG_LOGGER_ERROR(mLog,
"Failed to write samples to VILLASnode interface. "
"Write returned code {}",
ret);

/* Don't throw here, because we managed to send something */
}
Expand All @@ -386,7 +385,7 @@ void InterfaceWorkerVillas::configureExport(UInt attributeId,
const String &unit) {
if (mOpened) {
if (mLog != nullptr) {
SPDLOG_LOGGER_WARN(mLog, "InterfaceVillas has already been opened! "
SPDLOG_LOGGER_WARN(mLog, "VILLASnode interface has already been opened! "
"Configuration will remain unchanged.");
}
return;
Expand Down Expand Up @@ -489,7 +488,7 @@ void InterfaceWorkerVillas::configureImport(UInt attributeId,
UInt idx) {
if (mOpened) {
if (mLog != nullptr) {
SPDLOG_LOGGER_WARN(mLog, "InterfaceVillas has already been opened! "
SPDLOG_LOGGER_WARN(mLog, "VILLASnode interface has already been opened! "
"Configuration will remain unchanged.");
}
return;
Expand Down
3 changes: 2 additions & 1 deletion dpsim/include/dpsim/Interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class Interface : public SharedFactory<Interface> {

Interface(std::shared_ptr<InterfaceWorker> intf, const String &name = "",
UInt downsampling = 1)
: mInterfaceWorker(intf), mName(name), mDownsampling(downsampling) {
: mInterfaceWorker(intf), mName(name), mDownsampling(downsampling),
mOpened(false) {
mQueueDpsimToInterface = std::make_shared<
moodycamel::BlockingReaderWriterQueue<AttributePacket>>();
mQueueInterfaceToDpsim = std::make_shared<
Expand Down
20 changes: 11 additions & 9 deletions examples/villas/dpsim-file.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# This example demonstrates the export of values calculated by dpsim to a file using the VILLASnode interface

import json

import dpsimpy
import dpsimpyvillas

Expand Down Expand Up @@ -39,16 +41,16 @@
sim.set_time_step(time_step)
sim.set_final_time(final_time)

file_config = '''{
"type": "file",
"format": "csv",
"uri": "logs/output.csv",
"out": {
"flush": true
}
}'''
intf_config = {
'type': 'file',
'format': 'csv',
'uri': 'logs/output.csv',
'out': {
'flush': True
}
}

intf = dpsimpyvillas.InterfaceVillas(file_config, name='dpsim-file')
intf = dpsimpyvillas.InterfaceVillas(name='dpsim-file', config=json.dumps(intf_config))
intf.export_attribute(evs.attr('i_intf').derive_coeff(0, 0), 0)

sim.add_interface(intf)
Expand Down
19 changes: 11 additions & 8 deletions examples/villas/dpsim-mqtt-cigre-mv-pf-profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
import os
import sys
import json

import dpsimpy
import dpsimpyvillas
Expand Down Expand Up @@ -55,16 +56,18 @@
logger = dpsimpy.Logger(name)

# setup VILLASnode
intf_mqtt = dpsimpyvillas.InterfaceVillas(name='MQTT', config='''{
"type": "mqtt",
"host": "mqtt",
"in": {
"subscribe": "mqtt-dpsim"
intf_mqtt_config = {
'type': 'mqtt',
'host': 'mqtt',
'in': {
'subscribe': 'mqtt-dpsim'
},
"out": {
"publish": "dpsim-mqtt"
'out': {
'publish': 'dpsim-mqtt'
}
}''')
}

intf_mqtt = dpsimpyvillas.InterfaceVillas(name='MQTT', config=json.dumps(intf_mqtt_config))

# setup simulation
sim = dpsimpy.RealTimeSimulation(name)
Expand Down
28 changes: 14 additions & 14 deletions examples/villas/dpsim-mqtt-import-export-MIMO.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,31 +155,31 @@ def dpsim():
sim.log_attribute('n2.v', n1.attr('v'))

intf_config = {
"type": "mqtt",
"format": "json",
"host": "mqtt",
"in": {
"subscribe": "/mqtt-dpsim"
'type': 'mqtt',
'format': 'json',
'host': 'mqtt',
'in': {
'subscribe': '/mqtt-dpsim'
},
"out": {
"publish": "/dpsim-mqtt"
'out': {
'publish': '/dpsim-mqtt'
}
}

intf_config_2 = {
"type": "shmem",
"in": {
"name": "/shmem-dpsim"
'type': 'shmem',
'in': {
'name': '/shmem-dpsim'
},
"out": {
"name": "/dpsim-shmem"
'out': {
'name': '/dpsim-shmem'
}
}

intf = dpsimpyvillas.InterfaceVillas(name="dpsim-mqtt", config=intf_config)
intf = dpsimpyvillas.InterfaceVillas(name='dpsim-mqtt', config=json.dumps(intf_config))
sim.add_interface(intf)

intf2 = dpsimpyvillas.InterfaceVillas(name="dpsim-shmem", config=intf_config_2)
intf2 = dpsimpyvillas.InterfaceVillas(name='dpsim-shmem', config=json.dumps(intf_config_2))
sim.add_interface(intf2)
intf.import_attribute(load.attr('P'), 0)
intf.export_attribute(n1.attr('v').derive_coeff(0,0), 0)
Expand Down
Loading
Loading