Skip to main content

Crate uf_ulog

Crate uf_ulog 

Source
Expand description

§uf-ulog

CI codecov crates.io docs.rs

uf_ulog is an allocator-free ULog serializer designed for embedded targets.

§Features

  • no_std, allocator-free core.
  • MCU and transport agnostic (you provide writer/IO).
  • Supports both derive-based and manual trait implementations.
  • Split into two crates:
    • uf_ulog (core serializer)
    • uf_ulog_macro (derive macros)

§Supported messages (current scope)

The initial implementation focuses on:

  • Data messages (topic payloads) (D type)
  • String log messages (plain and tagged) (L and Ca types)
  • Parameter messages, (P type)
  • Required format messages needed to describe logged data/strings (B, F, )

§Cargo feature flags

  • derive (default): enables #[derive(ULogData)] and #[derive(ULogRegistry)].
  • async: enables async exporter support via embedded-io-async.

§Installation

Add uf-ulog to your Cargo.toml:

[dependencies]
uf-ulog = "*" # replace * by the latest version of the crate.

Or use the command line:

cargo add uf-ulog

§Examples

Based on examples/minimal.rs:

use std::convert::Infallible;

use uf_ulog::LogLevel;
use uf_ulog::ULogCoreExporter;
use uf_ulog::ULogData;
use uf_ulog::ULogProducer;
use uf_ulog::ULogRegistry;

#[derive(ULogData, Debug)]
struct Acc {
    timestamp: u64,
    x: f32,
    y: f32,
    z: f32,
}

#[derive(ULogData, Debug)]
struct Gyro {
    timestamp: u64,
    x: f32,
    y: f32,
    z: f32,
}

#[derive(ULogRegistry)]
pub enum UlogDataMessages {
    Gyro,
    Acc,
}

#[derive(Default)]
struct PrintWriter;

impl embedded_io::ErrorType for PrintWriter {
    type Error = Infallible;
}

impl embedded_io::Write for PrintWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
        println!("{:?}", buf);
        Ok(buf.len())
    }

    fn flush(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }
}

fn main() {
    let timestamp = 1772079727637;
    let producer = ULogProducer::<UlogDataMessages>::new();
    let mut exporter = ULogCoreExporter::<_, UlogDataMessages>::new(PrintWriter)
        .start(timestamp)
        .unwrap();

    let g = Gyro {
        timestamp,
        x: 1.0,
        y: 2.0,
        z: 3.0,
    };
    let a = Acc {
        timestamp,
        x: 1.0,
        y: 2.0,
        z: 9.0,
    };

    let record_data_gyro = producer.data::<Gyro>(&g).unwrap();
    let record_data_acc_instance = producer.data_instance::<Acc>(&a, 1).unwrap();
    let record_log_info = producer.log(LogLevel::Info, 43, "info log");
    let record_log_info_tagged = producer.log_tagged(LogLevel::Info, 1, 43, "info log");
    // Usually records produced by one task in non blocking fashion
    // to make sure that control loops are fast as possible. Records
    // then sent over channel to IO task, that may block or
    // take longer to offload data over compatible bus/net.
    exporter.accept(record_data_gyro).unwrap();
    exporter.accept(record_data_acc_instance).unwrap();
    exporter.accept(record_log_info).unwrap();
    exporter.accept(record_log_info_tagged).unwrap();
}

Run it:

cargo run -p uf_ulog --example minimal

§Write ULog to file and parse with pyulog

For an end-to-end demo (write a .ulg file, then parse it with Python), use:

just demo

This runs the example in ../examples/simple-file and then executes ../examples/simple-file/read_ulg.py via uv.

§References

Structs§

FormatsPending
LoggedString
MessageMeta
Record
Registry
StreamingReady
Subscription
Topic
ULogCoreExporter
ULogProducer

Enums§

BuildError
EncodeError
ExportError
ExportStep
LogLevel
ParameterValue
RecordKind
RecordMeta
TrySendError

Traits§

TopicOf
ULogData
ULogRegistry

Derive Macros§

ULogData
ULogRegistry