Skip to main content

pamoja_mavlink/
lib.rs

1#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
2
3//! The MAVLink wire protocol for the pamoja SDK.
4//!
5//! MAVLink is the language drones speak: PX4 and ArduPilot autopilots and MAVSDK ground
6//! stations all exchange MAVLink frames, so talking to a vehicle means putting exactly the
7//! right bytes on the wire and trusting the bytes that come back. This crate is that byte
8//! layer, hand-written from the [MAVLink specification](https://mavlink.io) and pinned to
9//! its reference values rather than guessed from memory:
10//!
11//! - [`crc16_mcrf4xx`] - the CRC-16/MCRF4XX every frame carries, the checksum that lets a
12//!   receiver reject a frame mangled in transit, anchored to the catalog check value.
13//! - [`Frame`] - the v1 and v2 frame on the wire, which both [assembles](Frame::encode_v2)
14//!   a frame to send and [parses](Frame::parse) one received, verifying the checksum and
15//!   the per-message [`message_crc_extra`] seed so a corrupt or mismatched frame never
16//!   reaches the application.
17//! - [`Parser`] - a streaming parser that turns the bytes a link delivers into whole
18//!   frames, resynchronizing on noise so a serial port or UDP socket just works.
19//! - [`signing`] - MAVLink 2 message signing: the SHA-256 signature and the monotonic
20//!   timestamp that let a ground station trust a command came from the vehicle it expects
21//!   and was not replayed.
22//! - [`dialect`] - a broad, typed slice of the common dialect (HEARTBEAT, the command,
23//!   parameter, and mission protocols, and core telemetry), each message with every MAVLink 2
24//!   extension field the dialect defines, plus message shapes as data: a
25//!   [`MessageDescriptor`](dialect::MessageDescriptor) gives any message's bytes named
26//!   fields, and a [builder](dialect::MessageDescriptorBuilder) describes one this crate
27//!   does not type, so a vendor or private dialect is usable at runtime. Every enumeration
28//!   a typed message's fields name is there in full, as constants and as a table of the
29//!   dialect's own names ([`ENUMS`](dialect::ENUMS)), so `MAV_STATE_STANDBY` reads as 3 and
30//!   3 reads back as `MAV_STATE_STANDBY`.
31//! - [`protocol`] - the mission, command, and offboard exchanges as pure, allocation-free
32//!   state machines: the rules of order, matching, and retransmission that turn single
33//!   messages into a real conversation with an autopilot, with no IO of their own. Each
34//!   machine also takes a [`Frame`] at a time and hands back the frame to send, so a
35//!   caller holding a link writes no decoding or dispatch of its own.
36//!
37//! The protocol core is `no_std` and allocation-free, so the same framing runs on a
38//! microcontroller flight controller. The default `std` feature adds the async layer: the
39//! byte-stream link seam and an in-process software-in-the-loop autopilot ([`link`]), the
40//! [`vehicle`] device model that presents an autopilot as a pamoja `Device`, and the real
41//! [`drivers`] (UDP, TCP, and serial behind the `serial` feature) that carry MAVLink to a real
42//! or simulated autopilot.
43//!
44//! # Examples
45//!
46//! ```
47//! use pamoja_mavlink::dialect::{mav_autopilot, mav_state, mav_type, Heartbeat, Message};
48//! use pamoja_mavlink::{Frame, Header};
49//!
50//! // Announce this node as an onboard controller that is up and running.
51//! let heartbeat = Heartbeat {
52//!     custom_mode: 0,
53//!     type_: mav_type::ONBOARD_CONTROLLER,
54//!     autopilot: mav_autopilot::GENERIC,
55//!     base_mode: 0,
56//!     system_status: mav_state::ACTIVE,
57//!     mavlink_version: 3,
58//! };
59//!
60//! // Encode it into a v2 frame, then read it back the way a peer would.
61//! let mut payload = [0u8; 255];
62//! let len = heartbeat.encode(&mut payload);
63//! let frame = Frame::encode_v2(Header::new(1, 1, 0), Heartbeat::ID, &payload[..len], Heartbeat::CRC_EXTRA)?;
64//!
65//! let received = Frame::parse(frame.as_bytes(), Heartbeat::CRC_EXTRA)?;
66//! let decoded = Heartbeat::decode(received.payload())?;
67//! assert_eq!(decoded.system_status, mav_state::ACTIVE);
68//! # Ok::<(), pamoja_mavlink::MavlinkError>(())
69//! ```
70
71#[cfg(feature = "alloc")]
72extern crate alloc;
73
74mod crc;
75pub mod dialect;
76mod error;
77mod frame;
78mod parser;
79pub mod protocol;
80pub mod signing;
81
82#[cfg(feature = "std")]
83pub mod link;
84
85#[cfg(feature = "std")]
86pub mod vehicle;
87
88#[cfg(feature = "std")]
89pub mod drivers;
90
91pub use crc::{accumulate, checksum, crc16_mcrf4xx, message_crc_extra};
92pub use error::{MavlinkError, Result};
93pub use frame::{
94    Frame, Header, Version, IFLAG_SIGNED, MAGIC_V1, MAGIC_V2, MAX_FRAME, MAX_PAYLOAD, SIGNATURE_LEN,
95};
96pub use parser::Parser;
97pub use signing::{Signer, Verifier};
98
99#[cfg(feature = "std")]
100pub use vehicle::{Report, Setpoint, Vehicle};
101
102#[cfg(feature = "std")]
103pub use drivers::{TcpLink, UdpLink};
104
105#[cfg(feature = "serial")]
106pub use drivers::SerialLink;