datactl/datatypes.h
datactl/datatypes.h
Namespaces
| Name |
|---|
| Syntalos |
Classes
| Name | |
|---|---|
| struct | Syntalos::supports_buffer_reuse |
| struct | Syntalos::supports_buffer_reuse< Frame > |
| struct | Syntalos::BaseDataType Base interface for all data types. |
| struct | Syntalos::ControlCommand A control command to a module. |
| struct | Syntalos::TableRow A new row for a table. |
| struct | Syntalos::FirmataControl Commands to control Firmata output. |
| struct | Syntalos::FirmataData Output data returned from a Firmata device. |
| struct | Syntalos::IntSignalBlock A block of integer signal data from a data source. |
| struct | Syntalos::FloatSignalBlock A block of floating-point signal data from an analog data source. |
Defines
| Name | |
|---|---|
| SY_DEFINE_DATA_TYPE(TypeName) Helper macro to define a Syntalos stream data type. |
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-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 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 <memory>
#include <string>
#include <vector>
#include <charconv>
#include <cstdint>
#include <cassert>
#include <array>
#include <cmath>
#include "syclock.h"
#include "binarystream.h"
#include "eigenaux.h"
namespace Syntalos
{
template<typename T>
struct supports_buffer_reuse : std::false_type {
};
// Frame carries a cv::Mat whose pixel buffer can be reused
struct Frame;
template<>
struct supports_buffer_reuse<Frame> : std::true_type {
};
enum class ModuleState : uint16_t {
UNKNOWN,
INITIALIZING,
IDLE,
PREPARING,
DORMANT,
READY,
RUNNING,
ERROR
};
struct BaseDataType {
public:
virtual ~BaseDataType() = default;
enum TypeId {
Unknown,
ControlCommand,
TableRow,
Frame,
FirmataControl,
FirmataData,
IntSignalBlock,
FloatSignalBlock,
Last
};
static std::string typeIdToString(int value)
{
if (value < 1 || value >= TypeId::Last)
return "<<unknown>>";
return typeIdToString(static_cast<TypeId>(value));
}
static std::string typeIdToString(TypeId value)
{
switch (value) {
case Unknown:
return "Unknown";
case ControlCommand:
return "ControlCommand";
case TableRow:
return "TableRow";
case Frame:
return "Frame";
case FirmataControl:
return "FirmataControl";
case FirmataData:
return "FirmataData";
case IntSignalBlock:
return "IntSignalBlock";
case FloatSignalBlock:
return "FloatSignalBlock";
default:
return "<<unknown>>";
}
}
static TypeId typeIdFromString(const std::string &str)
{
if (str == "Unknown")
return TypeId::Unknown;
if (str == "ControlCommand")
return TypeId::ControlCommand;
if (str == "TableRow")
return TypeId::TableRow;
if (str == "Frame")
return TypeId::Frame;
if (str == "FirmataControl")
return TypeId::FirmataControl;
if (str == "FirmataData")
return TypeId::FirmataData;
if (str == "IntSignalBlock")
return TypeId::IntSignalBlock;
if (str == "FloatSignalBlock")
return TypeId::FloatSignalBlock;
return TypeId::Unknown;
}
[[nodiscard]] virtual TypeId typeId() const = 0;
[[nodiscard]] 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 bool toBytes(ByteVector &output) 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;
std::string command;
explicit ControlCommand()
: duration(0)
{
}
explicit ControlCommand(ControlCommandKind ckind)
: kind(ckind),
duration(0)
{
}
void setDuration(ulong value)
{
duration = milliseconds_t(value);
}
[[nodiscard]] ulong getDurationAsInt() const
{
return duration.count();
}
bool toBytes(ByteVector &output) const override
{
BinaryStreamWriter stream(output);
stream.write(kind);
stream.write(static_cast<uint64_t>(duration.count()));
stream.write(command);
return true;
}
static ControlCommand fromMemory(const void *memory, size_t size)
{
ControlCommand obj;
BinaryStreamReader stream(memory, size);
uint64_t durationValue;
stream.read(obj.kind);
stream.read(durationValue);
stream.read(obj.command);
obj.duration = milliseconds_t(durationValue);
return obj;
}
};
struct TableRow : BaseDataType {
SY_DEFINE_DATA_TYPE(TableRow)
std::vector<std::string> data;
explicit TableRow() = default;
explicit TableRow(const std::vector<std::string> &row)
: data(row)
{
}
void reserve(int size)
{
data.reserve(size);
}
void append(const std::string &t)
{
data.push_back(t);
}
[[nodiscard]] int length() const
{
return data.size();
}
bool toBytes(ByteVector &output) const override
{
BinaryStreamWriter stream(output);
stream.write(data);
return true;
}
static TableRow fromMemory(const void *memory, size_t size)
{
TableRow obj;
BinaryStreamReader stream(memory, size);
stream.read(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};
std::string 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, std::string name = std::string())
: command(kind),
pinId(pinId),
pinName(std::move(name)),
isPullUp(false),
value(0)
{
}
FirmataControl(FirmataCommandKind kind, std::string name)
: command(kind),
pinName(std::move(name)),
isPullUp(false),
value(0)
{
}
bool toBytes(ByteVector &output) const override
{
BinaryStreamWriter stream(output);
stream.write(command);
stream.write(pinId);
stream.write(pinName);
stream.write(isOutput);
stream.write(isPullUp);
stream.write(value);
return true;
}
static FirmataControl fromMemory(const void *memory, size_t size)
{
FirmataControl obj;
BinaryStreamReader stream(memory, size);
stream.read(obj.command);
stream.read(obj.pinId);
stream.read(obj.pinName);
stream.read(obj.isOutput);
stream.read(obj.isPullUp);
stream.read(obj.value);
return obj;
}
};
struct FirmataData : BaseDataType {
SY_DEFINE_DATA_TYPE(FirmataData)
uint8_t pinId;
std::string pinName;
uint16_t value;
bool isDigital;
microseconds_t time;
bool toBytes(ByteVector &output) const override
{
BinaryStreamWriter stream(output);
stream.write(pinId);
stream.write(pinName);
stream.write(value);
stream.write(isDigital);
stream.write(static_cast<int64_t>(time.count()));
return true;
}
static FirmataData fromMemory(const void *memory, size_t size)
{
FirmataData obj;
BinaryStreamReader stream(memory, size);
int64_t timeUs;
stream.read(obj.pinId);
stream.read(obj.pinName);
stream.read(obj.value);
stream.read(obj.isDigital);
stream.read(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)
{
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;
bool toBytes(ByteVector &output) const override
{
BinaryStreamWriter stream(output);
serializeEigen(stream, timestamps);
serializeEigen(stream, data);
return true;
}
static IntSignalBlock fromMemory(const void *memory, size_t size)
{
IntSignalBlock obj;
BinaryStreamReader stream(memory, size);
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)
{
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;
bool toBytes(ByteVector &output) const override
{
BinaryStreamWriter stream(output);
serializeEigen(stream, timestamps);
serializeEigen(stream, data);
return true;
}
static FloatSignalBlock fromMemory(const void *memory, size_t size)
{
FloatSignalBlock obj;
BinaryStreamReader stream(memory, size);
obj.timestamps = deserializeEigen<VectorXul>(stream);
obj.data = deserializeEigen<MatrixXd>(stream);
return obj;
}
};
void registerStreamMetaTypes();
std::vector<std::pair<std::string, int>> streamTypeIdIndex();
template<typename T>
inline std::string numToString(T x)
requires std::is_arithmetic_v<T>
{
if constexpr (std::is_same_v<T, bool>) {
return x ? "true" : "false";
} else {
// Handle floating-point special cases
if constexpr (std::is_floating_point_v<T>) {
if (std::isnan(x))
return "nan";
if (std::isinf(x))
return std::signbit(x) ? "-inf" : "inf";
if (x == 0.0)
x = 0.0; // canonicalize -0 to +0
}
std::array<char, 128> buf{};
std::to_chars_result result{};
if constexpr (std::is_floating_point_v<T>) {
result = std::to_chars(buf.data(), buf.data() + buf.size(), x, std::chars_format::general);
} else {
result = std::to_chars(buf.data(), buf.data() + buf.size(), x);
}
if (result.ec != std::errc{}) {
assert(false);
return "<<conversion error>>";
}
return {buf.data(), result.ptr};
}
}
} // namespace Syntalos
Updated on 2026-03-16 at 19:16:01 +0000