mavspec 0.1.0-alpha7

A set of code generation utilities for MAVLink protocol.
Documentation
MAVSpec
=======

A code-generator for [MAVLink](https://mavlink.io/en/).

[`repository`](https://gitlab.com/mavka/libs/mavspec)
[`crates.io`](https://crates.io/crates/mavspec)
[`API docs`](https://docs.rs/mavspec/latest/mavspec/)
[`issues`](https://gitlab.com/mavka/libs/mavspec/-/issues)

MAVLink is a lightweight open protocol for communicating between drones, onboard components and ground control stations.
It is used by such autopilots like [PX4](https://px4.io) or [ArduPilot](https://ardupilot.org/#). MAVLink has simple and
compact serialization model. The basic abstraction is `message` which can be sent through the link (UDP, TCP, UNIX
socket, UART, whatever) and deserialized into a struct with fields of primitive types or arrays of primitive types.
Such fields can be additionally restricted by `enum` variants, annotated with metadata like units of measurements,
default or invalid values. There are several MAVLink dialects. Official dialect definitions are
[XML files](https://mavlink.io/en/guide/xml_schema.html) that can be found in the MAVlink
[repository](https://github.com/mavlink/mavlink/tree/master/message_definitions/v1.0). Based on `message` abstractions,
MAVLink defines so-called [`microservices`](https://mavlink.io/en/services/) that specify how clients should respond on
a particular message under certain conditions or how they should initiate a particular action.

This library is a building block for other MAVLink-related tools (telemetry collectors, IO, etc.). It is only responsible
for code generation. Other [Mavka](https://mavka.gitlab.io/home/) projects are focused on different areas:

* [MAVInspect]https://gitlab.com/mavka/libs/mavspec responsible for parsing mavlink message XML definitions. MAVSpec 
  is using this it to discover and parse MAVLink dialects.
* [Mavio]https://gitlab.com/mavka/libs/mavio, a minimalistic library for transport-agnostic MAVLink communication
  written in Rust. It supports `no-std` (and `no-alloc`) targets and focuses on stateless parts of MAVLink protocol.
* [Maviola]https://gitlab.com/mavka/libs/maviola (WIP), an elaborated MAVLink communication library based on `Mavio`
  that takes care about stateful features: sequencing, message time-stamping, automatic heartbeats, simplifies message
  signing, and so on.

This project respects [`semantic versioning`](https://semver.org).

Install
-------

Install as a Cargo dependency.

```shell
cargo add --build mavspec
```

Since you probably want to generate code as a part of you build sequence, we suggest to also add MAVSpec as a build
dependency.

```shell
cargo add --build mavspec
```

Usage
-----

> The following explains how to use library API, for command-line tool usage check [CLI]#cli section.

### Rust

API documentation for Rust code-generation can be found [here](https://docs.rs/mavspec/latest/mavspec/rust).

Add MAVSpec with `rust` feature to your `Cargo.toml`.

```toml
[dependencies]
#...
mavspec = { version = "0.1.0", features = ["rust"] }
#...
```

This feature enables interfaces upon which your generated code will depend. You can access these interfaces through
`use mavspec::rust::spec`.

Optionally enable `std` (for Rust standard library) or `alloc` (for memory allocation support) features if your target
supports them (if you are not developing for an embedded devices, then we suggest to always enable `std`).

Add MAVSpec with `rust_gen` as a build dependency:

```toml
[build-dependencies]
#...
mavspec = { version = "0.1.0", features = ["rust_gen"] }
#...
```

If necessary, add optional section to your `Cargo.toml` to generate only specific messages:

```toml
[package.metadata.mavspec]
messages = ["HEARTBEAT", "PROTOCOL_VERSION", "MAV_INSPECT_V1", "COMMAND_INT", "COMMAND_LONG"]
all_enums = false
generate_tests = false
```

This will greatly reduce compile time and may slightly reduce memory footprint (if you are not going to expose
autogenerated code as a part of your library API, then Rust compiler will probably optimize away all unused pieces). 

The `all_enum` key controls which enums will be generated. By default, only MAVLink enums required for selected messages
will be generated. Set `all_enums = true` to generate all enums. If `messages` key is not specified, then `all_enums`
won't have any effect.

If you want to generate tests for generated code, set `generate_tests` to `true`. This mode is disabled by default.

Update your `build.rs`:

```rust
use std::env::var;
use std::path::Path;

use mavspec::rust::BuildHelper;

fn main() {
    // Assume that your library and `message_definitions` are both in the root of your project.
    let sources = vec![
        "./message_definitions/standard",
        "./message_definitions/extra",
    ];
    // Output path
    let destination = Path::new(&var("OUT_DIR").unwrap()).join("mavlink");
    // Path to your `Cargo.toml` manifest
    let manifest_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml");

    // Parse XML definitions and generate Rust code
    BuildHelper::builder(&destination)
        .set_sources(&sources)
        .set_manifest_path(&manifest_path)
        .generate()
        .unwrap();
}
```

The `OUT_DIR` environment variable is provided by Rust build toolchain and points to output library for your crate. It
is considered a bad practice to write outside this path in the build scripts.

Finally, import generated code in your `lib.rs` (or anywhere it seems appropriate):

```rust
mod mavlink {
    include!(concat!(env!("OUT_DIR"), "/mavlink/mod.rs"));
}
pub use mavlink::dialects;
```

Check [`examples/rust`](examples/rust/README.md) for a slightly more elaborated example which uses Cargo features as flags for MAVLink
dialect selection.

CLI
---

Parse XML definitions from [`./message_definitions/standard`](./message_definitions/standard) and generate dialects in
`tmp/mavlink` directory:

```shell
cargo run --bin mavspec -- --src message_definitions/standard --out tmp/mavlink rust
```

Print `mavspec` help for Rust code generator:

```shell
cargo run --bin mavspec -- rust -h
```

Examples
--------

- [`examples/rust`]examples/rust/README.md — an example library with autogenerated code.
  ```shell
  cargo run --package mavspec_examples_rust --bin mavspec_examples_rust
  ```

License
-------

> Here we simply comply with the suggested dual licensing according to
> [Rust API Guidelines]https://rust-lang.github.io/api-guidelines/about.html (C-PERMISSIVE).

Licensed under either of

* Apache License, Version 2.0
  ([LICENSE-APACHE]LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license
  ([LICENSE-MIT]LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

Contribution
------------

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.