What's new in microblx (dev)?

January 14, 2026 — updated 2026-07-01

Although quiet on the master branch, a lot is going on on -dev. Here's a summary of what's coming (and will become the long awaited v1.0).

new blocks

lsdb-intf and ubx-dbus

A D-Bus interface block that exposes the full node API (create/remove blocks, connect ports, set/get configs, load USC models, ...) over D-Bus. The companion ubx-dbus CLI provides interactive access from the shell.

The plugin extension lets you register custom D-Bus objects at runtime by loading Lua plugin files, so application-specific interfaces can sit alongside the standard org.ubx.node API.

The block is based on the lsdbus bindings. Essentially, this permits creating coordination interfaces that can cleanly and safely interact with the hard real-time processing without impacting real-time performance.

lfrb

A new lock-free ring buffer iblock based on a minimal internal liblfq implementation which is based on a Vyukov MPMC queue. This replaces the external liblfds dependency which didn't support arm64. Strongly typed, hard-real-time safe.

gpio

Linux GPIO block using libgpiod v2. Ports are created dynamically from the gpios config array — each input line becomes an out-port, each output line becomes an in-port (type unsigned int). Supports active-low polarity, pull bias, and emit-on-change mode.

iio

Linux Industrial I/O blocks via libiio for ADCs, DACs, IMUs, and environmental sensors. Two variants:

  • ubx/iiopolled, synchronous sysfs read each step; also supports DAC output
  • ubx/iio_bufbuffered, hardware samples at sampling_frequency; ptrig drains the kernel buffer

Ports are created dynamically from the channels config; type is always double (physical scaled value).

gps

GPS block that reads from gpsd via its shared memory interface. Emits a single gps out-port of type ubx_gps_data with position, velocity, fix quality, and uncertainty fields.

webgraph

A luablock that serves an interactive browser graph of the running node using React Flow + ELK.js. Blocks are shown as nodes (colour-coded by state) with ports, configs, and iblock edges. The page auto-refreshes and re-runs the ELK layered layout. Requires luasocket and json.lua; JS libs are fetched from CDN on first load. Self-trigger it at a low rate alongside your composition — no separate process needed.

ubx-launch gained a matching -webgraph [PORT] flag to attach one automatically:

$ ubx-launch -c threshold.usc -webgraph

webgraph showing the threshold example composition

This replaces the old webif block, which was removed — it had grown too complex and unmaintainable.

math_double / math_float

Applies any single-argument math.h function element-wise to an input array, with optional per-element mul and add (y = f(x) * mul + add). The function is selected via the func config string ("sin", "sqrt", "log", etc.).

netsink

A luablock-based streaming sink for live-plotting and telemetry (primarily PlotJuggler). It drains input ports and emits one message per sample over the network. Two transports — UDP datagrams or a ZeroMQ PUB socket — and two encodings — JSON or MessagePack — are selectable, all via lua_str globals. Ports are created dynamically from the ports declaration:

{ name="sink", type="luablock:netsink" },
-- ...
{ name="sink", config = {
     lua_str = [[
        ports     = { x="double", v="double" }
        transport = "zmq"          -- "udp" (default) or "zmq"
        format    = "msgpack"      -- "json" (default) or "msgpack"
        uri       = "tcp://*:9870"
     ]],
} },

Both transports go straight through the LuaJIT FFI — no luasocket or lzmq dependency. For RT decoupling, run the sink on its own thread at a lower rate (thread=1, period=100) with deep connection buffers (buffer_len=N); each step drains the full buffer so no samples are lost on the RT side.

$ ubx-launch -c netsink.usc

netsink streaming sin/cos/tan to PlotJuggler over UDP

(Previously called udpsink; renamed now that it does more than UDP — the migration is a one-word type change.)

other changes

blockdiagram: direct luablock loading

.usc compositions can now instantiate Lua blocks directly using the luablock:NAME type prefix — no need to manually import the luablock module, create an instance, and configure lua_file separately:

blocks = {
    { name="ctrl", type="luablock:mycontroller" },
},

The name is resolved against the standard microblx block prefixes.

luablock: self-triggering

luablock now supports built-in self-triggering via the thread and period configs. For non-RT management or interfacing tasks this eliminates the need for a dedicated ptrig:

config = { thread=1, period=100 }  -- self-trigger at 100 ms

preinit / preexit life-cycle hooks

Blocks gained two optional life-cycle hooks, preinit and preexit, running before the regular init/cleanup. They add a second structural-mutation point for the rare case where a block must build its own interface from its configuration — e.g. create ports whose number or type depends on a config, or a config whose value drives the creation of other configs. This is what lets netsink above turn its ports declaration into real ports before the connections are wired up.

Most blocks never need thisinit remains the place for ordinary setup. Reach for preinit only when interface creation has to depend on configuration. It's available to C blocks and to luablock (just define Lua preinit/preexit functions); the rationale is written up in docs/dev/004.

ptrig: SCHED_DEADLINE support

ptrig now supports Linux EDF scheduling via sched_policy = "SCHED_DEADLINE". Timing parameters are passed via the sched_deadline config (runtime_ns, deadline_ns, period_ns); deadline_ns and period_ns default to the period config when 0. After each chain trigger sched_yield signals budget exhaustion to the kernel. Budget overruns are caught via SIGXCPU and counted on the deadline_throt_cnt out-port. The sched_deadline in-port allows runtime parameter updates without reconfiguration.

ptrig: dynamic period port

ptrig gained a period in-port for runtime adjustment of the trigger period without reconfiguration.

const: runtime in port

ubx/cconst and ubx/iconst gained an in port. Writing to it updates the held value at runtime — without a reconfigure cycle. Example use-case: update dynamic configuration safely via the lsdb-intf block.

ubx-log: syslog forwarding and daemon mode

ubx-log gained two new options: -s tees log messages to syslog (selectable facility via -f LOCAL0..7), and -d daemonizes via libdaemon with a PID file under /run to prevent duplicate instances.

improved enum, struct and union support

Anonymous structs and unions are now handled correctly by cdata.tolua. Named structs and unions gained a custom converter registration mechanism, and enums are properly reflected, with new test coverage throughout.

register (struct) types from Lua

New ubx.type_add(nd, name, cdecl [, doc]) registers a struct type at runtime — no build-time ubx-typegen step or separate C type module needed. It does the ffi.cdef + ffi.sizeof + persistent copy + ubx_type_register in one call, and ubx.type_rm(nd, name) unregisters and frees one it created:

ubx.type_add(nd, "struct point", "struct point { double x; double y; };")
local d = ubx.data_alloc(nd, "struct point")   -- usable like any other type

The registered type is a real, fully-formed ubx_type_t: allocatable, marshallable to/from Lua tables, and visible to tooling. It is node-local (the hash is name-based) — meant for self-contained nodes, not for data crossing a process boundary. This lets a luablock expose a genuine typed config instead of smuggling structured configuration through lua_str. See docs/dev/005.

Lua API docs

ubx.lua is now fully documented with ldoc. The generated API reference is published here and built as part of the standard CMake doc target.

build: switched to CMake

The build system was migrated from make to CMake, reducing boilerplate and improving IDE and cross-compilation support.

test cleanup

Tests were reorganised into suites with a single runner, CI was updated to Debian trixie, and the lsdb-intf tests are now part of the standard CI run.

various bug fixes

Several minor fixes across ubx.lua, blockdiagram, node cleanup, module reloading, and timing utilities.