datactl/datatypes.h

datactl/datatypes.h

datactl/datatypes.h

Namespaces

Name
Syntalos

Classes

Name
structBaseDataType
Base interface for all data types.
structControlCommand
Helper function to get the type ID of a data type.
structTableRow
A new row for a table.
structFirmataControl
Commands to control Firmata output.
structFirmataData
Output data returned from a Firmata device.
structIntSignalBlock
A block of integer signal data from a data source.
structFloatSignalBlock
A block of floating-point signal data from an analog data source.

Types

Name
enum classConnectionHeatLevel { NONE, LOW, MEDIUM, HIGH}
Connection heat level.
enum class uint16_tModuleState { UNKNOWN, INITIALIZING, IDLE, PREPARING, DORMANT, READY, RUNNING, ERROR}
The ModuleState enum.
enum classFirmataCommandKind { UNKNOWN, NEW_DIG_PIN, NEW_ANA_PIN, IO_MODE, WRITE_ANALOG, WRITE_DIGITAL, WRITE_DIGITAL_PULSE, SYSEX}
The FirmataCommandKind enum.
enum classSignalDataType { Amplifier, AuxInput, SupplyVoltage, BoardAdc, BoardDigIn, BoardDigOut}
Type of a signal from a signal source.

Functions

Name
QStringconnectionHeatToHumanString(ConnectionHeatLevel heat)
voidregisterStreamMetaTypes()
Helper function to register all meta types for stream data.
QMap< QString, int >streamTypeIdMap()
Get a mapping of type names to their IDs.

Defines

Name
SY_DEFINE_DATA_TYPE(TypeName)
Helper macro to define a Syntalos stream data type.

Types Documentation

enum ConnectionHeatLevel

EnumeratorValueDescription
NONE
LOW
MEDIUM
HIGH

Connection heat level.

Helpers to (de)serialize enum classes into streams, in case we are compiling with older versions of Qt.

Warning level dependent on how full the buffer that is repesented by a connection is. A high heat means lots of pending stuff and potentially a slow receiving module or not enough system resources. This state is managed internally by Syntalos.

enum ModuleState

EnumeratorValueDescription
UNKNOWN
INITIALIZINGModule is in an unknown state.
IDLEModule is initializing after being added.
PREPARINGModule is inactive and not started.
DORMANTModule is preparing a run.
READYThe module is inactive for this run, as it has no work to do.
RUNNINGEverything is prepared, we are ready to start.
ERRORModule is running. Module failed to run / is in an error state

The ModuleState enum.

Describes the state a module can be in. The state is usually displayed to the user via a module indicator widget.

enum FirmataCommandKind

EnumeratorValueDescription
UNKNOWN
NEW_DIG_PIN
NEW_ANA_PIN
IO_MODE
WRITE_ANALOG
WRITE_DIGITAL
WRITE_DIGITAL_PULSE
SYSEXnot implemented

The FirmataCommandKind enum.

Set which type of change should be made on a Firmata interface.

enum SignalDataType

EnumeratorValueDescription
Amplifier
AuxInput
SupplyVoltage
BoardAdc
BoardDigIn
BoardDigOut

Type of a signal from a signal source.

This is usually set in the metadata of a data stream.

Functions Documentation

function connectionHeatToHumanString

QString connectionHeatToHumanString(
    ConnectionHeatLevel heat
)

function registerStreamMetaTypes

void registerStreamMetaTypes()

Helper function to register all meta types for stream data.

This function registers all types with the meta object system and also creates a global map of all available stream types.

function streamTypeIdMap

QMap< QString, int > streamTypeIdMap()

Get a mapping of type names to their IDs.

Macros Documentation

define SY_DEFINE_DATA_TYPE

#define SY_DEFINE_DATA_TYPE(
    TypeName
)
BaseDataType::TypeId typeId() const override         \
    {                                                    \
        return BaseDataType::TypeName;                   \
    }                                                    \
    static constexpr BaseDataType::TypeId staticTypeId() \
    {                                                    \
        return BaseDataType::TypeName;                   \
    }

Helper macro to define a Syntalos stream data type.

Source code

/*
 * Copyright (C) 2019-2024 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 software 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 software.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <QDataStream>
#include <QMetaType>
#include <QMetaEnum>
#include <memory>

#include "syclock.h"
#include "eigenaux.h"

using namespace Syntalos;

Q_DECLARE_SMART_POINTER_METATYPE(std::shared_ptr)


#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
template<typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type &operator<<(QDataStream &s, const T &t)
{
    return s << static_cast<typename std::underlying_type<T>::type>(t);
}

template<typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type &operator>>(QDataStream &s, T &t)
{
    return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t);
}
#endif

enum class ConnectionHeatLevel {
    NONE,
    LOW,
    MEDIUM,
    HIGH
};
Q_DECLARE_METATYPE(ConnectionHeatLevel)

QString connectionHeatToHumanString(ConnectionHeatLevel heat);

enum class ModuleState : uint16_t {
    UNKNOWN,      
    INITIALIZING, 
    IDLE,         
    PREPARING,    
    DORMANT,      
    READY,        
    RUNNING,      
    ERROR         
};
Q_DECLARE_METATYPE(ModuleState)


struct BaseDataType {
    Q_GADGET
public:
    enum TypeId {
        Unknown,
        ControlCommand,
        TableRow,
        Frame,
        FirmataControl,
        FirmataData,
        IntSignalBlock,
        FloatSignalBlock,
        Last
    };
    Q_ENUM(TypeId)

    static QString typeIdToString(TypeId value)
    {
        const auto metaEnum = QMetaEnum::fromType<TypeId>();
        return QString(metaEnum.valueToKey(static_cast<int>(value)));
    }

    static QString typeIdToString(int value)
    {
        if (value < 1 || value >= TypeId::Last)
            return QStringLiteral("<<unknown>>");
        return typeIdToString(static_cast<TypeId>(value));
    }

    static TypeId typeIdFromString(const QString &str)
    {
        const auto metaEnum = QMetaEnum::fromType<TypeId>();
        bool ok;
        auto enumVal = static_cast<TypeId>(metaEnum.keyToValue(str.toLatin1(), &ok));
        if (ok)
            return enumVal;
        else
            return TypeId::Unknown;
    }

    virtual TypeId typeId() const = 0;

    virtual ssize_t memorySize() const
    {
        // Size is not known in advance
        return -1;
    }

    virtual bool writeToMemory(void *memory, ssize_t size = -1) const
    {
        return false;
    };

    virtual QByteArray toBytes() const = 0;
};

#define SY_DEFINE_DATA_TYPE(TypeName)                    \
    BaseDataType::TypeId typeId() const override         \
    {                                                    \
        return BaseDataType::TypeName;                   \
    }                                                    \
    static constexpr BaseDataType::TypeId staticTypeId() \
    {                                                    \
        return BaseDataType::TypeName;                   \
    }

template<typename T>
constexpr int syDataTypeId()
    requires std::is_base_of_v<BaseDataType, T>
{
    return T::staticTypeId();
}

template<typename T>
T deserializeFromMemory(const void *memory, size_t size)
    requires std::is_base_of_v<BaseDataType, T>
{
    return T::fromMemory(memory, size);
}

enum class ControlCommandKind {
    UNKNOWN,
    START, 
    PAUSE, 
    STOP,  
    STEP,  
    CUSTOM
};

struct ControlCommand : BaseDataType {
    SY_DEFINE_DATA_TYPE(ControlCommand)

    ControlCommandKind kind{ControlCommandKind::UNKNOWN}; 
    milliseconds_t duration; 
    QString command;         

    explicit ControlCommand()
        : duration(0)
    {
    }
    explicit ControlCommand(ControlCommandKind ckind)
        : kind(ckind),
          duration(0)
    {
    }

    void setDuration(ulong value)
    {
        duration = milliseconds_t(value);
    }

    ulong getDurationAsInt() const
    {
        return duration.count();
    }

    QByteArray toBytes() const override
    {
        QByteArray bytes;
        QDataStream stream(&bytes, QIODevice::WriteOnly);

        stream << kind << (quint64)duration.count() << command;

        return bytes;
    }

    static ControlCommand fromMemory(const void *memory, size_t size)
    {
        ControlCommand obj;

        QByteArray block(reinterpret_cast<const char *>(memory), size);
        QDataStream stream(block);

        quint64 durationValue;
        stream >> obj.kind >> durationValue >> obj.command;
        obj.duration = milliseconds_t(durationValue);

        return obj;
    }
};

struct TableRow : BaseDataType {
    SY_DEFINE_DATA_TYPE(TableRow)

    QList<QString> data;

    explicit TableRow() {}
    explicit TableRow(const QList<QString> &row)
        : data(row)
    {
    }

    void reserve(int size)
    {
        data.reserve(size);
    }

    void append(const QString &t)
    {
        data.append(t);
    }

    int length() const
    {
        return data.length();
    }

    QByteArray toBytes() const override
    {
        QByteArray bytes;
        QDataStream stream(&bytes, QIODevice::WriteOnly);

        stream << data;

        return bytes;
    }

    static TableRow fromMemory(const void *memory, size_t size)
    {
        TableRow obj;
        QByteArray block(reinterpret_cast<const char *>(memory), size);
        QDataStream stream(block);

        stream >> obj.data;

        return obj;
    }
};

enum class FirmataCommandKind {
    UNKNOWN,
    NEW_DIG_PIN,
    NEW_ANA_PIN,
    IO_MODE,
    WRITE_ANALOG,
    WRITE_DIGITAL,
    WRITE_DIGITAL_PULSE,
    SYSEX 
};

struct FirmataControl : BaseDataType {
    SY_DEFINE_DATA_TYPE(FirmataControl)

    FirmataCommandKind command;
    uint8_t pinId{0};
    QString pinName;
    bool isOutput{false};
    bool isPullUp{false};
    uint16_t value;

    explicit FirmataControl()
        : command(FirmataCommandKind::UNKNOWN),
          value(0)
    {
    }

    explicit FirmataControl(FirmataCommandKind cmd)
        : command(cmd),
          isPullUp(false),
          value(0)
    {
    }

    FirmataControl(FirmataCommandKind kind, int pinId, QString name = QString())
        : command(kind),
          pinId(pinId),
          pinName(std::move(name)),
          isPullUp(false),
          value(0)
    {
    }

    FirmataControl(FirmataCommandKind kind, QString name)
        : command(kind),
          pinName(std::move(name)),
          isPullUp(false),
          value(0)
    {
    }

    QByteArray toBytes() const override
    {
        QByteArray bytes;
        QDataStream stream(&bytes, QIODevice::WriteOnly);

        stream << command << pinId << pinName << isOutput << isPullUp << value;

        return bytes;
    }

    static FirmataControl fromMemory(const void *memory, size_t size)
    {
        FirmataControl obj;
        QByteArray block(reinterpret_cast<const char *>(memory), size);
        QDataStream stream(block);

        stream >> obj.command >> obj.pinId >> obj.pinName >> obj.isOutput >> obj.isPullUp >> obj.value;

        return obj;
    }
};

struct FirmataData : BaseDataType {
    SY_DEFINE_DATA_TYPE(FirmataData)

    uint8_t pinId;
    QString pinName;
    uint16_t value;
    bool isDigital;
    microseconds_t time;

    QByteArray toBytes() const override
    {
        QByteArray bytes;
        QDataStream stream(&bytes, QIODevice::WriteOnly);

        stream << pinId << pinName << value << isDigital << static_cast<qint64>(time.count());

        return bytes;
    }

    static FirmataData fromMemory(const void *memory, size_t size)
    {
        FirmataData obj;
        QByteArray block(reinterpret_cast<const char *>(memory), size);
        QDataStream stream(block);

        qint64 timeUs;
        stream >> obj.pinId >> obj.pinName >> obj.value >> obj.isDigital >> timeUs;
        obj.time = microseconds_t(timeUs);

        return obj;
    }
};

enum class SignalDataType {
    Amplifier,
    AuxInput,
    SupplyVoltage,
    BoardAdc,
    BoardDigIn,
    BoardDigOut
};

struct IntSignalBlock : BaseDataType {
    SY_DEFINE_DATA_TYPE(IntSignalBlock)

    explicit IntSignalBlock(uint sampleCount = 60, uint channelCount = 1)
    {
        Q_ASSERT(channelCount > 0);
        timestamps.resize(sampleCount);
        data.resize(sampleCount, channelCount);
    }

    size_t length() const
    {
        return timestamps.size();
    }

    size_t rows() const
    {
        return data.rows();
    }
    size_t cols() const
    {
        return data.cols();
    }

    VectorXul timestamps;
    MatrixXsi data;

    QByteArray toBytes() const override
    {
        QByteArray bytes;
        QDataStream stream(&bytes, QIODevice::WriteOnly);

        serializeEigen(stream, timestamps);
        serializeEigen(stream, data);

        return bytes;
    }

    static IntSignalBlock fromMemory(const void *memory, size_t size)
    {
        IntSignalBlock obj;
        QByteArray block(reinterpret_cast<const char *>(memory), size);
        QDataStream stream(block);

        obj.timestamps = deserializeEigen<VectorXul>(stream);
        obj.data = deserializeEigen<MatrixXsi>(stream);

        return obj;
    }
};

struct FloatSignalBlock : BaseDataType {
    SY_DEFINE_DATA_TYPE(FloatSignalBlock)

    explicit FloatSignalBlock(uint sampleCount = 60, uint channelCount = 1)
    {
        Q_ASSERT(channelCount > 0);
        timestamps.resize(sampleCount);
        data.resize(sampleCount, channelCount);
    }

    explicit FloatSignalBlock(const std::vector<float> &floatVec, uint timestamp)
    {
        timestamps.array() += timestamp;
        data.resize(1, floatVec.size());
        for (size_t i = 0; i < floatVec.size(); ++i)
            data(0, i) = floatVec[i];
    }

    size_t length() const
    {
        return timestamps.size();
    }

    size_t rows() const
    {
        return data.rows();
    }
    size_t cols() const
    {
        return data.cols();
    }

    VectorXul timestamps;
    MatrixXd data;

    QByteArray toBytes() const override
    {
        QByteArray bytes;
        QDataStream stream(&bytes, QIODevice::WriteOnly);

        serializeEigen(stream, timestamps);
        serializeEigen(stream, data);

        return bytes;
    }

    static FloatSignalBlock fromMemory(const void *memory, size_t size)
    {
        FloatSignalBlock obj;
        QByteArray block(reinterpret_cast<const char *>(memory), size);
        QDataStream stream(block);

        obj.timestamps = deserializeEigen<VectorXul>(stream);
        obj.data = deserializeEigen<MatrixXd>(stream);

        return obj;
    }
};

void registerStreamMetaTypes();

QMap<QString, int> streamTypeIdMap();

class VariantDataStream;
namespace Syntalos
{
class VarStreamInputPort;
class AbstractModule;

} // namespace Syntalos

Updated on 2024-09-05 at 17:39:59 +0000