KymoCore · C++11 / C API

Telemetry for your MCU or SoC, without the overhead.

KymoCore reads your measurements at the configured rate, packs them into binary frames of 9 to 21 bytes and hands them to any interface – without heap, RTOS or blocking the main loop. On the PC, KymoStudio shows the signals live.

256 channels, own rate

Each channel has its own sampling interval; a round-robin scheduler decides whose turn it is.

Y, XY or XYZ

Optionally with a timestamp and CRC-8. float32, little endian, a fixed and documented protocol.

Never blocks

Kymo_Init() once, Kymo_Main() in the loop. No heap, RTOS, exceptions or RTTI.

Any interface

UART, USB CDC, Wi-Fi with TCP or UDP, MQTT, CAN – you provide a write callback, KymoCore provides the bytes.

Slow links included

Partial writes, backpressure and borrowed DMA buffers are handled cleanly.

Runtime tracing

Opt-in macros for scopes, markers, ISRs and scheduler switches. KYMO_ENABLED=0 compiles everything out for production.

Quick start

Install from the PlatformIO Registry

Add KymoCore to the platformio.ini of your project:

lib_deps =
    codename666/KymoCore

Complete example for Arduino and ESP32

This src/main.cpp sends a sawtooth between 0 and just below 1 on channel 0 every 20 ms with the default settings. The serial interface carries only binary data – diagnostic prints would corrupt the stream.

#include <Arduino.h>
#include <kymo_runtime.h>

static KymoContext context = {};
static KymoStatus lastStatus = KYMO_BAD_CONFIG;
static uint32_t lastSampleMs[1] = {};
static const KymoChannel channels[] = {{20U, 0U, 0U}};

static uint32_t readClockMs(void *user)
{
    (void)user;
    return static_cast<uint32_t>(millis());
}

static uint8_t readSample(void *user, uint8_t id, KymoSample *out)
{
    (void)user;
    (void)id;
    if (out == nullptr) {
        return 0U;
    }
    out->value = static_cast<float>(millis() % 1000UL) / 1000.0f;
    return 1U;
}

static uint8_t writeBytes(void *user, const uint8_t *bytes, uint8_t length)
{
    int available = Serial.availableForWrite();
    (void)user;
    if ((bytes == nullptr) || (available <= 0)) {
        return 0U;
    }
    if (available < length) {
        length = static_cast<uint8_t>(available);
    }
    return static_cast<uint8_t>(Serial.write(bytes, length));
}

static const KymoConfig config = {
    channels, lastSampleMs, readClockMs, nullptr, readSample, nullptr,
    writeBytes, nullptr, nullptr, nullptr, 1U
};

void setup()
{
    Serial.begin(115200);
    lastStatus = Kymo_Init(&context, &config);
}

void loop()
{
    if ((lastStatus != KYMO_BAD_CONFIG) && (lastStatus != KYMO_IO_ERROR)) {
        lastStatus = Kymo_Main(&context);
    }
}

Build with pio run, flash with pio run -t upload, close any serial monitor and connect KymoStudio at 115200 baud, 8N1. Assign channel 0 to a chart.

Supported targets

KymoCore contains no hardware drivers: you integrate your target through time, sampling and transport callbacks. That keeps it the same from an Arduino Uno to an STM32 with DMA. The KymoProbe examples cover Arduino Uno, Nano and Mega; ESP32, ESP32-S3 and ESP32-C3; STM32 Nucleo F401RE, F411RE and Blue Pill F103C8 – these are example ports, not a restriction.

License

KymoCore is dual-licensed: GPLv3, free of charge for hobby, learning and open-source projects, or a commercial license for firmware and devices distributed without disclosing your source code. Details are in the licensing terms.

Protocol specification →   Guide and API reference →   All KymoCore features →