Crate mavio

Source
Expand description

Β§Mavio

Minimalistic library for transport-agnostic MAVLink communication. It supports no-std (and no-alloc) targets.

πŸ‡ΊπŸ‡¦ repository crates.io docs.rs issues

This library is a part of Mavka toolchain. It focuses on I/O and uses MAVSpec to generate MAVLink dialects.

Β§Features

Mavio is focused on I/O primitives for MAVLink that can be used in no-std and no-alloc environments. Since Mavio is designed as a building block for more sophisticated tools, it includes absolute minimum of functionality required for correct communication with everything that speaks MAVLink protocol.

Β§Basic capabilities

  • Mavio supports both MAVLink 1 and MAVLink 2 protocol versions.
  • Provides intermediate MAVLink packets decoding with Frame that contain only header, checksum and signature being deserialized. Which means that client don’t have to decode the entire message for routing and verification.
  • Supports optional high-level message decoding by utilizing MAVLink abstractions generated by MAVSpec.
  • Includes standard MAVLink dialects enabled by cargo features.
  • Implements message verification via checksum.
  • Provides a mechanism for message sequencing through Endpoint::next_frame, that encodes a MAVLink message into a Frame with a correct sequence as required by MAVLink protocol.
  • Includes tools for message signing.

Β§Flexible approach to I/O

Mavio is designed to be flexible and useful in different scenarios.

  • It can work without any MAVLink dialect at all (for intermediate decoding and proxying).
  • Includes support for custom payload decoders and encoders. Which means that clients are not bounded by abstractions generated by MAVSpec.
  • Uses implementation-agnostic I/O primitives with a variety of I/O adapters.
  • Provides synchronous I/O adapters for embedded-io and std::io.
  • Supports asynchronous I/O by providing lightweight adapters for embedded-io-async, Tokio, and futures-rs.

Such features are mainly related to the functionality provided by other parts of Mavka toolchain. These tasks are mainly performed by MAVInspect and MAVSpec (a message definition parser and code-generator respectively). In particular:

  • Mavio allows to use custom MAVLink dialects. This includes both dialects generated from XML definitions and ad-hoc dialects defined with pure Rust.
  • Respects dialect inheritance. Messages defined in one dialect are not redefined upon inclusion into another dialect. This means that if you have a message M from dialect A being included by dialect B, it guaranteed that you can use Rust structs for message M with both of the dialects. The same is true for MAVLink enums and bitmasks.
  • Provides optional support for MAVLink microservices as sub-dialects and helpers to work with them such as mission file format.

Β§Serialization / deserialization and FFI

Mavio provides support for serde and specta. The latter is supported only for std targets. All MAVLink entities are fully supported.

Β§Out of scope

There are few stateful features required by MAVLink protocol this library intentionally does not implement and leaves for the client:

  • Sending automatic heartbeats. This is required by most of the clients which would consider nodes without heartbeats as inactive or invalid.
  • Stateful timestamp management for message signing (ensuring, that two messages are not sent with the same timestamp).
  • Retry logic for failed connections.

All such features are provided by Maviola.

Β§Usage

This library exposes Sender and Receiver to send and receive instances of MAVLink Frame. Frames contain encoded message body in Frame::payload and additional fields (such as sequence or system_id) as required by MAVLink specification. Once frame is received, it can be decoded into a specific Message. Frame decoding requires dialect specification which can be either generated manually by using MAVSpec or by enabling built-in dialect features.

Upon receiving or building a frame, it can be converted into a protocol-agnostic MavFrame, that hides generic version parameter of a Frame.

Β§Receive

Connect to TCP port and receive first 10 MAVLink frames, decode any received HEARTBEAT messages.

use std::net::TcpStream;

use mavio::prelude::*;
use mavio::dialects::minimal as dialect;

use dialect::Minimal;

// Create a TCP client receiver
let reader = StdIoReader::new(TcpStream::connect("0.0.0.0:5600")?);
let mut receiver = Receiver::versionless(reader);

for i in 0..10 {
    let frame = receiver.recv()?;

    // Validate MAVLink frame
    if let Err(err) = frame.validate_checksum::<Minimal>() {
        eprintln!("Invalid checksum: {err:?}");
        continue;
    }

    if let Ok(Minimal::Heartbeat(msg)) = frame.decode() {
        println!(
            "HEARTBEAT #{}: mavlink_version={:#?}",
            frame.sequence(),
            msg.mavlink_version,
        );
    }
}

Β§Send

Connect to TCP port and send 10 HEARTBEAT messages using MAVLink 2 protocol.

use std::net::TcpStream;

use mavio::prelude::*;
use mavio::dialects::minimal as dialect;
use dialect::enums::{MavAutopilot, MavModeFlag, MavState, MavType};

// Create a TCP client sender
let writer = StdIoWriter::new(TcpStream::connect("0.0.0.0:5600")?);
let mut sender = Sender::new(writer);

// Create an endpoint that represents a MAVLink device speaking `MAVLink 2` protocol
let endpoint = Endpoint::v2(MavLinkId::new(15, 42));

// Create a message
let message = dialect::messages::Heartbeat {
    type_: MavType::FixedWing,
    autopilot: MavAutopilot::Generic,
    base_mode: MavModeFlag::TEST_ENABLED & MavModeFlag::CUSTOM_MODE_ENABLED,
    custom_mode: 0,
    system_status: MavState::Active,
    mavlink_version: dialect::Minimal::version().unwrap(),
};
println!("MESSAGE: {message:?}");

for i in 0..10 {
    // Build the next frame for this endpoint.
    // All required fields will be populated, including frame sequence counter.
    let frame = endpoint.next_frame(&message)?;

    sender.send(&frame)?;
    println!("FRAME #{} sent: {:#?}", i, frame);
}

Β§I/O adapters

We provide lightweight Read / Write and AsyncRead / AsyncWrite pairs for synchronous and asynchronous I/O.

Mavio packages a set of I/O adapters available under the corresponding feature flags:

See adapters for details.

We use MAVSpec to generate MAVLink entities and additional abstractions. These entities are bundled with Mavio for better user experience and to prevent discrepancies in crate versions.

Β§Dialects

Standard MAVLink dialect can be enabled by the corresponding feature flags (dlct-<dialect name>).

  • minimal β€” minimal dialect required to expose your presence to other MAVLink devices.
  • standard β€” a superset of minimal dialect, that expected to be used by almost all flight stack.
  • common β€” minimum viable dialect with most of the features, a building block for other future-rich dialects.
  • ardupilotmega β€” feature-full dialect used by ArduPilot. In most cases this dialect is the go-to choice if you want to recognize almost all MAVLink messages used by existing flight stacks.
  • all β€” meta-dialect which includes all other standard dialects including those which were created for testing purposes. It is guaranteed that namespaces of the dialects in all family do not collide.
  • Other dialects from MAVLink XML definitions: asluav, avssuas, csairlink, cubepilot, development, icarous, matrixpilot, paparazzi, ualberta, uavionix. These do not include python_array_test and test dialects which should be either generated manually or as a part of all meta-dialect.

For example:

use mavio::dialects::common as dialect;
use dialect::{Common, messages::Heartbeat};
use mavio::prelude::*;

let frame: Frame<V2> = /* obtain a frame */

// Decode MavLink frame into a dialect message:
match frame.decode()? {
    Common::Heartbeat(msg) => {
        /* process heartbeat */
    }
    /* process other messages */
};

Β§Default dialect

When standard MAVLink dialects are used and at least dlct-minimal Cargo feature is enabled, this library exposes default_dialect and DefaultDialect entities that allow to access the most feature-rich enabled MAVLink dialect. Other features such as microservices or microservice utils are based on this convention.

The sequence of default dialects is the following (in the order of the increased completeness):

  • minimal β€” enabled by dlct-minimal feature flag
  • standard β€” enabled by dlct-standard feature flag
  • common β€” enabled by dlct-common feature flag
  • ardupilotmega β€” enabled by dlct-ardupilotmega feature flag
  • all β€” enabled by dlct-all feature flag

Β§Microservices

Mavio re-exports MAVLink microservices from MAVSpec. To control which microservices you want to generate, use msrv-* feature flags family. Check MAVSpec API docs for details.

At the moment, microservices are generated only for default_dialect and can be accessed through microservices.

Β§Microservice utils

In addition, Mavio re-exports extra tools for working with microservices. These tools can be enabled by msrv-utils-* feature flags and available in microservices::utils module and bundled inside the corresponding microservice.

`msrv-utils-*` are considered unstable for now! Use `unstable` feature flag to enable them.

Β§Message definitions

It is possible to bundle message definitions generated by MAVInspect into definitions module. This can be useful for ground control stations that require to present the user with the descriptions of MAVLink entities.

To enable definitions bundling use definitions feature flag.

Message definitions available only with `std` feature enabled. Otherwise, this will cause build to fail.

Β§Metadata

MAVSpec can generate additional metadata such as MAVLink enum entry names. This can be a useful addition to MAVlink definitions when ground stations are considered. To enable metadata support, use metadata feature flag.

Β§Caveats

The API is straightforward and generally stable, however, some caution is required when working with edge-cases.

Β§Unsafe Features

This library does not use unsafe Rust, however, certain manipulations on MAVLink frames, if not performed carefully, could lead to data corruption and undefined behavior. All such operations are covered by unsafe cargo features and marked with ⚠ in the documentation.

Most of the unsafe operations are related to updating existing frames in-place. In general, situations when you need mutable access to frames are rare. If your use-case does not strictly require such manipulations, we suggest to refrain from using functionality hidden under the unsafe feature flags.

Β§Unstable Features

Certain features are considered unstable and available only when unstable feature flag is enabled. Unstable features are marked with ⍚ and are may be changed in futures versions.

Β§Incompatible Features

  • Specta requires std feature to be enabled.
  • MAVlink definitions requires std feature to be enabled.

Β§Binary Size

For small applications that use only a small subset of messages, avoid using dialect enums as they contain all message variants. Instead, decode messages directly from frames:

use mavio::dialects::common as dialect;
use dialect::messages::Heartbeat;
use mavio::prelude::*;

let frame: Frame<V2> = /* obtain a frame */

// Use only specific messages:
match frame.message_id() {
    Heartbeat::ID => {
        let msg = Heartbeat::try_from(frame.payload())?;
        /* process heartbeat */
    }
    /* process other messages */
};

This will help compiler to throw away unnecessary pieces of code.

Additionally, you may use microservices as well as microservices::utils to reduce API surface you are interacting with.

Β§Feature flags

In most of the cases you will be interested in dlct-* features to access MAVLink dialects, I/O adapters, and alloc / std target specification. However, a more fine-grained control may be required.

Β§Generic features

  • default β€” Default features (nothing is enabled).
  • unstable β€” Enable unstable API features.
  • extras β€” Additional auxilary tools.
  • unsafe β€” Unsafe features, that allow access to internal state of the entities.
  • alloc β€” Enable memory allocation support.
  • std β€” Enable Rust std library.
  • sha2 β€” Enable sha2 backend for message signing

Β§Serialization and reflection

These features enable serde and specta support.

  • serde β€” Enable serde support.
  • specta β€” Enable specta support.

Β§I/O providers

These features enable I/O providers such as Tokio or embedded-io

  • futures β€” Enable async support via futures-rs
  • tokio β€” Enable async support via Tokio
  • embedded-io β€” Enable synchronous I/O support from embedded HAL
  • embedded-io-async β€” Enable asynchronous I/O support from embedded HAL

Β§MAVSpec tools

These features package additional MAVSpec utils suc as derive macros and message definitions.

  • derive β€” Adds derive macros for MAVLink entities.

    You can access them as mavio::derive.

  • definitions β€” Bundles MAVLink message definitions.

    Message definitions will be generated only for bundled MAVLink dialects. Microservices will be ignored as they are just subsets of existing dialects.

    Note, that while being useful for ground control stations, the generated definitions is quite large and may bloat the size of the binary.

    ⚠️ This feature won’t compile without std feature enabled.

  • metadata β€” Adds additional metadata to MAVLink entities.

Β§Dialects

Bundle standard MAVLink dialects as defined in XML message definitions generated by MAVSpec.

All enabled dialects can be found in dialects module. The default dialect, if available, can be found in default_dialect or as a DefaultDialect.

  • dlct-ardupilotmega β€” Include ardupilotmega dialect

    The dialect can be found in dialects::ardupilotmega module.

  • dlct-asluav β€” Include ASLUAV dialect

    The dialect can be found in dialects::asluav module.

  • dlct-avssuas β€” Include AVSSUAS dialect

    The dialect can be found in dialects::avssuas module.

  • dlct-common β€” Include common dialect

    The dialect can be found in dialects::common module.

  • dlct-cs_air_link β€” Include csAirLink dialect

    The dialect can be found in dialects::cs_air_link module.

  • dlct-cubepilot β€” Include cubepilot dialect

    The dialect can be found in dialects::cubepilot module.

  • dlct-development β€” Include development dialect

    The dialect can be found in dialects::development module.

  • dlct-icarous β€” Include icarous dialect

    The dialect can be found in dialects::icarous module.

  • dlct-matrixpilot β€” Include matrixpilot dialect

    The dialect can be found in dialects::matrixpilot module.

  • dlct-minimal β€” Include minimal dialect

    The dialect can be found in dialects::minimal module.

  • dlct-paparazzi β€” Include paparazzi dialect

    The dialect can be found in dialects::paparazzi module.

  • dlct-standard β€” Include standard dialect

    The dialect can be found in dialects::standard module.

  • dlct-ualberta β€” Include ualberta dialect

    The dialect can be found in dialects::ualberta module.

  • dlct-uavionix β€” Include uAvionix dialect

    The dialect can be found in dialects::u_avionix module.

  • dlct-all β€” Include all meta-dialect

    The dialect can be found in dialects::all module.

These features will control generation of MAVLink microservice-specific bindings.

If enabled, microservices can be found in microservices module.

These features will enable additional MAVLink utilities such as *.waypoints files support, mission planninc, etc.

⚠️ All such features require unstable feature to be enabled in order to take effect.

  • msrv-utils-all β€” All MAVLink microservices utils

    ⚠️ Requires unstable feature to take effect.

  • msrv-utils-mission β€” Mission protocol utils

    ⚠️ Requires unstable feature to take effect.

Β§Technical features

These features should not be used directly.

  • msrv β€” βŠ› Enable MAVLink microservices support

    Do not use directly as this feature does not give access to any specific functionality by itself. Instead, use one of msrv-* features.

  • msrv-utils β€” βŠ›οΈ Enables MAVLink microservices extra utils

    Do not use directly as this feature does not give access to any specific functionality by itself. Instead, use one of msrv-utils-* features.

Modules§

consts
Constants
default_dialect
mavspec Default MAVLink dialect module
definitions
mavspec MAVLink message definitions
derive
mavspec MAVSpec procedural macros
dialects
mavspec MAVLink dialects
error
Errors
io
Basic MAVLink I/O
mavspec
mavspec MAVSpec re-exported
microservices
mavspec MAVLink microservices
prelude
Common imports
protocol
MAVLink protocol
utils
Utils

Structs§

AsyncReceiver
Receives MAVLink frames asynchronously.
AsyncSender
Sends MAVLink frames asynchronously.
Endpoint
MAVLink device with defined ID and internal frame sequence counter.
Frame
MAVLink frame.
MavLinkId
mavspec MAVLink device ID.
Receiver
Receives MAVLink frames.
Sender
Sends MAVLink frames.

Enums§

DefaultDialect
mavspec Default MAVLink dialect
Error
mavio top-level error.
MavFrame
Version-agnostic MAVLink frame, that can be matched according to its protocol version.

Traits§

Dialect
mavspec Interface for autogenerated or custom MAVLink dialect specification.
Message
mavspec MAVLink message implementation.

Type Aliases§

Result
Common result type returned by mavio functions and methods.