Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Building on Leviculum in Rust: Choosing a Layer

Leviculum is a Rust workspace, not a single crate. The Reticulum stack is split into layers so that the same protocol engine can run on a tokio server, a bare-metal nRF52 radio, or behind a C ABI. As an application developer your first decision is which layer you build against. This chapter explains the four crates, the dependency direction between them, and gives a decision table.

The companion chapters are the Rust API tutorial (a hands-on reticulum-std walkthrough), the Rust API reference (verified signatures of the key types), and Embedded development (building on reticulum-core directly). If you are writing C rather than Rust, the C API overview and How-To are your counterparts to those chapters.

The four layers

        reticulum-ffi  (C ABI)        reticulum-nrf  (nRF52 firmware)
              │                              │
              ▼                              │
        reticulum-std  (std, tokio)         │
              │                              │
              ▼                              ▼
                    reticulum-core  (no_std, sans-IO)

The dependency direction is strict and one-way. reticulum-std builds on reticulum-core; reticulum-ffi wraps reticulum-std; reticulum-nrf wraps reticulum-core directly (it never pulls in std or tokio). Nothing depends on a layer above it.

reticulum-core — the no_std, sans-IO engine

reticulum-core is the protocol. It is no_std (it pulls in alloc, but not the standard library), performs no I/O of its own, and owns no runtime. It is sans-IO: you feed it received bytes, it returns a TickOutput describing the packets to send and the events that occurred, and you dispatch those yourself. Time, persistence, and the network are abstracted behind three traits — Clock, Storage, and Interface — that you implement for your platform.

Build against reticulum-core when you have your own runtime or event loop and do not want tokio: embedded firmware, an integration into a different async executor, a simulator, or a host program that wants byte-level control. See Embedded development.

reticulum-std — the full std/tokio application layer

reticulum-std is what most Rust applications use. It supplies the platform pieces reticulum-core abstracts: a SystemClock, file-backed storage with Python-compatible on-disk formats, and concrete interfaces (TCP client and server, UDP, AutoInterface for LAN discovery, RNode/LoRa, raw serial). On top of those it runs the sans-IO core inside a tokio event loop and exposes an async, handle-based API: build a node with ReticulumNodeBuilder, start() it, take an EventReceiver, and use LinkHandle / PacketSender to send.

Build against reticulum-std when you are writing a normal Rust program on Linux/macOS that talks to a Reticulum mesh. This is the path the tutorial and the examples under reticulum-std/examples/ take.

reticulum-ffi — the C ABI wrapper

reticulum-ffi exposes reticulum-std through a C-compatible ABI: opaque handles, integer error codes, a pollable event fd. It is the layer behind leviculum.h and libleviculum.so. If you are writing Rust you do not use it — you use reticulum-std directly, which is what reticulum-ffi itself does internally. It exists so that non-Rust programs (C, and anything that can call a C library) get the same engine.

If your application is in C, stop here and read the C API overview and How-To instead; they are the C counterpart to this Rust documentation.

reticulum-nrf — the reference firmware

reticulum-nrf is standalone firmware for nRF52 boards (the T114 and RAK4631 LoRa nodes), built with the Embassy async embedded framework. It is version 0.4.0, targets thumbv7em-none-eabihf, and depends on reticulum-core directly with default-features = false — no std, no tokio. It is both a usable firmware and the worked reference for how to drive the sans-IO core on bare metal; the embedded chapter walks through its main loop.

You do not “build on” reticulum-nrf the way you build on a library; you fork it or read it as the canonical example of a reticulum-core integration on a real device.

Decision table

You are building…UseWhy
A Linux/macOS app or daemon talking to a meshreticulum-stdAsync handle API, real interfaces, file storage, tokio loop already wired
A drop-in tool reusing a running lnsd/rnsdreticulum-stdconnect_to_shared_instance over the shared-instance IPC
A relay / transport nodereticulum-stdenable_transport(true), see relay_daemon.rs
A C program (any non-Rust language with C FFI)reticulum-ffiStable C ABI, opaque handles, pollable fd — see the C API chapters
Firmware on an nRF52 LoRa boardreticulum-nrfReference firmware; fork or adapt it
Firmware on a different MCU / a custom async runtimereticulum-coreImplement Clock/Storage/Interface, drive the sans-IO loop yourself
A simulator or byte-level test harness with no I/Oreticulum-coreFeed bytes, inspect TickOutput, no runtime imposed

Adding the dependency

None of these crates are published on crates.io. Depend on them by path (in a workspace checkout) or by git. For a reticulum-std application:

# Path, when your crate lives next to the libreticulum checkout
[dependencies]
reticulum-std = { path = "../libreticulum/reticulum-std" }
tokio = { version = "1", features = ["full"] }

# Or by git
# reticulum-std = { git = "https://codeberg.org/…/libreticulum" }

For embedded work depend on reticulum-core instead, with default features off:

[dependencies]
reticulum-core = { path = "../libreticulum/reticulum-core", default-features = false }

The workspace is edition 2021, version 0.7.0 (the reticulum-nrf firmware tracks its own 0.4.0), and licensed AGPL-3.0-or-later.