1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00
VILLASnode/include/villas/nodes/iec61850_goose.hpp
Steffen Vogel 02a2aa4f94 Apply clang-format changes
Signed-off-by: Steffen Vogel <steffen.vogel@opal-rt.com>
2023-09-08 11:37:42 +02:00

259 lines
6.9 KiB
C++

/* Node type: IEC 61850 - GOOSE.
*
* Author: Philipp Jungkamp <philipp.jungkamp@rwth-aachen.de>
* SPDX-FileCopyrightText: 2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <array>
#include <condition_variable>
#include <cstdint>
#include <ctime>
#include <map>
#include <mutex>
#include <optional>
#include <string>
#include <thread>
#include <libiec61850/goose_publisher.h>
#include <libiec61850/goose_receiver.h>
#include <libiec61850/goose_subscriber.h>
#include <villas/node.hpp>
#include <villas/node/config.hpp>
#include <villas/pool.hpp>
#include <villas/queue_signalled.h>
#include <villas/signal.hpp>
namespace villas {
namespace node {
namespace iec61850 {
// A GooseSignal is a SignalData value with attached Metadata for the MmsType and SignalType
class GooseSignal {
public:
union Meta {
int size;
};
struct Descriptor {
std::string name;
SignalType signal_type;
MmsType mms_type;
Meta default_meta;
};
using Type = Descriptor const *;
// The config file identifier for this type
std::string const &name() const;
// The type of this value
Type type() const;
// Corresponding mms type
MmsType mmsType() const;
// Corresponding signal type
SignalType signalType() const;
// Create a GooseSignal from an MmsValue
static std::optional<GooseSignal> fromMmsValue(MmsValue *mms_value);
// Create a GooseSignal from type name and SignalData value
static std::optional<GooseSignal>
fromNameAndValue(char const *name, SignalData value,
std::optional<Meta> meta = std::nullopt);
// Create a MmsValue from this GooseSignal
MmsValue *toMmsValue() const;
static std::optional<Type> lookupMmsType(int mms_type);
static std::optional<Type> lookupMmsTypeName(char const *name);
GooseSignal(Type type, SignalData value,
std::optional<Meta> meta = std::nullopt);
SignalData signal_data;
Meta meta;
private:
inline static std::array const descriptors{
Descriptor{"boolean", SignalType::BOOLEAN, MmsType::MMS_BOOLEAN},
Descriptor{
"int8", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 8}},
Descriptor{
"int16", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 16}},
Descriptor{
"int32", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 32}},
Descriptor{
"int64", SignalType::INTEGER, MmsType::MMS_INTEGER, {.size = 64}},
Descriptor{
"int8u", SignalType::INTEGER, MmsType::MMS_UNSIGNED, {.size = 8}},
Descriptor{
"int16u", SignalType::INTEGER, MmsType::MMS_UNSIGNED, {.size = 16}},
Descriptor{
"int32u", SignalType::INTEGER, MmsType::MMS_UNSIGNED, {.size = 32}},
Descriptor{"bitstring",
SignalType::INTEGER,
MmsType::MMS_BIT_STRING,
{.size = 32}},
Descriptor{
"float32", SignalType::FLOAT, MmsType::MMS_FLOAT, {.size = 32}},
Descriptor{
"float64", SignalType::FLOAT, MmsType::MMS_FLOAT, {.size = 64}},
};
static MmsValue *newMmsInteger(int64_t i, int size);
static MmsValue *newMmsUnsigned(uint64_t i, int size);
static MmsValue *newMmsBitString(uint32_t i, int size);
static MmsValue *newMmsFloat(double i, int size);
// Descriptor within the descriptors table above
Descriptor const *descriptor;
};
bool operator==(GooseSignal &lhs, GooseSignal &rhs);
bool operator!=(GooseSignal &lhs, GooseSignal &rhs);
class GooseNode : public Node {
protected:
enum InputTrigger {
CHANGE,
ALWAYS,
};
struct InputMapping {
std::string subscriber;
unsigned int index;
GooseSignal::Type type;
};
struct SubscriberConfig {
std::string go_cb_ref;
InputTrigger trigger;
std::optional<std::array<uint8_t, 6>> dst_address;
std::optional<uint16_t> app_id;
};
struct InputEventContext {
SubscriberConfig subscriber_config;
GooseNode *node;
std::vector<std::optional<GooseSignal>> values;
int last_state_num;
};
struct Input {
enum { NONE, STOPPED, READY } state;
GooseReceiver receiver;
CQueueSignalled queue;
Pool pool;
std::map<std::string, InputEventContext> contexts;
std::vector<InputMapping> mappings;
std::string interface_id;
bool with_timestamp;
unsigned int queue_length;
} input;
struct OutputData {
std::optional<unsigned int> signal;
GooseSignal default_value;
};
struct PublisherConfig {
std::string go_id;
std::string go_cb_ref;
std::string data_set_ref;
std::array<uint8_t, 6> dst_address;
uint16_t app_id;
uint32_t conf_rev;
uint32_t time_allowed_to_live;
int burst;
std::vector<OutputData> data;
};
struct OutputContext {
PublisherConfig config;
std::vector<GooseSignal> values;
GoosePublisher publisher;
};
struct Output {
enum { NONE, STOPPED, READY } state;
std::vector<OutputContext> contexts;
std::string interface_id;
double resend_interval;
std::mutex send_mutex;
bool changed;
bool resend_thread_stop;
std::optional<std::thread> resend_thread;
std::condition_variable resend_thread_cv;
} output;
void createReceiver() noexcept;
void destroyReceiver() noexcept;
void startReceiver() noexcept(false);
void stopReceiver() noexcept;
void createPublishers() noexcept;
void destroyPublishers() noexcept;
void startPublishers() noexcept(false);
void stopPublishers() noexcept;
static void onEvent(GooseSubscriber subscriber,
InputEventContext &context) noexcept;
void addSubscriber(InputEventContext &ctx) noexcept;
void pushSample(uint64_t timestamp) noexcept;
static void publish_values(GoosePublisher publisher,
std::vector<GooseSignal> &values, bool changed,
int burst = 1) noexcept;
static void resend_thread(GooseNode::Output *output) noexcept;
void parseInput(json_t *json);
void parseSubscriber(json_t *json, SubscriberConfig &sc);
void parseSubscribers(json_t *json,
std::map<std::string, InputEventContext> &ctx);
void parseInputSignals(json_t *json, std::vector<InputMapping> &mappings);
void parseOutput(json_t *json);
void parsePublisherData(json_t *json, std::vector<OutputData> &data);
void parsePublisher(json_t *json, PublisherConfig &pc);
void parsePublishers(json_t *json, std::vector<OutputContext> &ctx);
virtual int _read(struct Sample *smps[], unsigned cnt) override;
virtual int _write(struct Sample *smps[], unsigned cnt) override;
public:
GooseNode(const uuid_t &id = {}, const std::string &name = "");
virtual ~GooseNode() override;
virtual std::vector<int> getPollFDs() override;
virtual int parse(json_t *json) override;
virtual int prepare() override;
virtual int start() override;
virtual int stop() override;
};
} // namespace iec61850
} // namespace node
} // namespace villas