mlink/syntaloslinkmodule.h
mlink/syntaloslinkmodule.h
Namespaces
| Name |
|---|
| Syntalos |
Classes
| Name | |
|---|---|
| class | Syntalos::SyntalosLinkModule Convenience interface to write an OOP Syntalos module. |
| class | Syntalos::OutputPortLink Reference for an output port to emit new data. |
Source code
/*
* Copyright (C) 2020-2026 Matthias Klumpp <matthias@tenstral.net>
*
* Licensed under the GNU Lesser General Public License Version 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the license, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <iostream>
#include <syntalos-datactl>
#include "syntaloslink.h"
namespace Syntalos
{
template<typename T>
requires std::is_base_of_v<BaseDataType, T>
class OutputPortLink;
class SyntalosLinkModule
{
public:
explicit SyntalosLinkModule(SyntalosLink *slink);
virtual ~SyntalosLinkModule();
SyntalosLinkModule(const SyntalosLinkModule &) = delete;
SyntalosLinkModule &operator=(const SyntalosLinkModule &) = delete;
void raiseError(const std::string &message);
void raiseError(const std::string &title, const std::string &message);
void awaitData(int timeoutUsec = -1);
ModuleState state() const;
void setState(ModuleState state);
void setStatusMessage(const std::string &message);
virtual bool prepare();
virtual void start();
virtual void stop();
virtual void shutdown();
protected:
template<typename T>
T unwrapOrAbort(std::expected<T, std::string> result, std::string_view context = {})
{
if (!result) {
if (context.empty())
std::cerr << "Fatal: " << context << ": " << result.error() << std::endl;
else
std::cerr << "Fatal: " << result.error() << std::endl;
std::abort();
}
return std::move(*result);
}
[[nodiscard]] SyncTimer *timer() const;
const TestSubjectInfo &testSubject() const;
template<typename T>
requires std::is_base_of_v<BaseDataType, T>
auto registerOutputPort(const std::string &id, const std::string &title = {}, const MetaStringMap &metadata = {})
-> std::expected<std::shared_ptr<OutputPortLink<T>>, std::string>
{
// fetch existing output port first, if any exists
for (auto &eop : m_slink->outputPorts()) {
if (eop->id() == id)
return std::shared_ptr<OutputPortLink<T>>(new OutputPortLink<T>(this, eop));
}
// register a new port if we found none
auto opInfo = m_slink->registerOutputPort(
id, title, static_cast<BaseDataType::TypeId>(syDataTypeId<T>()), metadata);
if (!opInfo.has_value())
return std::unexpected(std::format("Failed to register output port with ID {}: {}", id, opInfo.error()));
auto oport = std::shared_ptr<OutputPortLink<T>>(new OutputPortLink<T>(this, *opInfo));
return oport;
}
template<typename T>
requires std::is_base_of_v<BaseDataType, T>
auto registerOutputPortOrAbort(
const std::string &id,
const std::string &title = {},
const MetaStringMap &metadata = {}) -> std::shared_ptr<OutputPortLink<T>>
{
return unwrapOrAbort(registerOutputPort<T>(id, title, metadata));
}
template<typename T, typename U>
requires std::is_base_of_v<BaseDataType, T>
auto registerInputPort(const std::string &id, const std::string &title, U *instance, void (U::*fn)(const T &data))
-> std::expected<std::shared_ptr<InputPortInfo>, std::string>
{
// fetch existing input port first, if any exists
for (auto &eip : m_slink->inputPorts()) {
if (eip->id() == id)
return eip;
}
auto res = m_slink->registerInputPort(id, title, static_cast<BaseDataType::TypeId>(syDataTypeId<T>()));
if (!res.has_value())
return res;
auto iport = *res;
iport->setNewDataRawCallback([instance, fn](const void *data, size_t size) {
std::invoke(fn, instance, T::fromMemory(data, size));
});
return iport;
}
template<typename T, typename U>
requires std::is_base_of_v<BaseDataType, T>
auto registerInputPortOrAbort(
const std::string &id,
const std::string &title,
U *instance,
void (U::*fn)(const T &data)) -> std::shared_ptr<InputPortInfo>
{
return unwrapOrAbort(registerInputPort<T, U>(id, title, instance, fn));
}
virtual void saveSettings(ByteVector &settings, const fs::path &baseDir);
virtual bool loadSettings(const ByteVector &settings, const fs::path &baseDir);
protected:
bool m_running;
private:
template<typename T>
requires std::is_base_of_v<BaseDataType, T>
friend class OutputPortLink;
class Private;
std::unique_ptr<Private> d;
SyntalosLink *m_slink;
};
template<typename T>
requires std::is_base_of_v<BaseDataType, T>
class OutputPortLink
{
public:
OutputPortLink(const OutputPortLink &) = delete;
OutputPortLink &operator=(const OutputPortLink &) = delete;
std::string id() const
{
return m_info->id();
}
int dataTypeId() const
{
return m_info->dataTypeId();
}
void setMetadataVar(const std::string &key, const MetaValue &value)
{
m_info->setMetadataVar(key, value);
m_mod->m_slink->updateOutputPort(m_info);
}
bool submit(const T &data)
{
return m_mod->m_slink->submitOutput(m_info, data);
}
private:
friend SyntalosLinkModule;
explicit OutputPortLink(SyntalosLinkModule *mod, std::shared_ptr<OutputPortInfo> pinfo)
{
m_mod = mod;
m_info = std::move(pinfo);
}
private:
std::shared_ptr<OutputPortInfo> m_info;
SyntalosLinkModule *m_mod;
};
} // namespace Syntalos
Updated on 2026-04-24 at 23:36:58 +0000