MAVLink v2 frame encoding and decoding, for a MAVLink2.Dialect.
Wire layout:
STX 0xFD (v2); 0xFE (v1) is refused on receive
len payload length after truncation
incompat_flags
compat_flags
seq
sysid 1 byte, or 4 (little endian) with SYSID32
compid
msgid 24-bit, little endian
target_sysid 4 bytes, little endian, with TARGET32 only
payload
checksum 16-bit LE, over everything after STX plus crc_extra
signature 13 bytes, with SIGNED onlyIncompat flags
| Bit | ||
|---|---|---|
0x01 | SIGNED | a signature follows the checksum; see MAVLink2.Signing |
0x02 | SYSID32 | sysid is 4 bytes. encode/2 sets it when sysid is over 255 |
0x04 | TARGET32 | the header carries target_sysid, which takes precedence over a payload target_system. encode/2 sets it when target_sysid is not nil |
A frame with any other bit is refused.
A message to a system id over 255 carries target_sysid and 255 in its
payload target_system.
Payload truncation
v2 drops trailing zero bytes from the payload on the wire, keeping at least one, and the receiver zero-extends it back to the message's length. A receiver that does not zero-extend misreads every short frame.
Decoded frames
raw is the frame's wire bytes, for forwarding it unchanged (a
re-encoded frame would lose its signature). known is false only for a
frame decoded with unknown: :keep whose id the dialect lacks: its
checksum was not checked and its payload is as received.
Summary
Types
@type t() :: %MAVLink2.Frame{ compat_flags: 0..255, compid: 0..255, incompat_flags: 0..255, known: boolean(), msgid: non_neg_integer(), payload: binary(), raw: nil | binary(), seq: 0..255, signature: nil | {link_id :: 0..255, timestamp :: non_neg_integer(), <<_::48>>, binary()}, sysid: 0..4_294_967_295, target_sysid: nil | 0..4_294_967_295 }
Functions
@spec decode(binary(), module(), keyword()) :: {:ok, t(), binary()} | {:incomplete, binary()} | {:error, term(), binary()}
Decode the first complete frame in bin.
{:ok, frame, rest}{:incomplete, bin}: more bytes needed; keepbin{:error, reason, rest}: resynchronise fromrest
Option unknown: is :skip (the default) or :keep, for an id the
dialect lacks.
Errors:
| Resumes | |
|---|---|
:no_stx | at the next STX, so a run of junk is one error |
:mavlink_v1_unsupported | after the v1 STX |
{:unsupported_incompat_flags, flags} | after the STX, as soon as the flags byte has arrived: an unknown flag may change the layout |
{:unknown_msgid, id} | with unknown: :skip, after the STX as soon as the header has arrived: without the message's crc_extra the frame cannot be checked, so its length byte cannot be trusted |
:bad_checksum | after the STX, since the length byte itself may be the corruption |
With unknown: :keep, a frame with an unknown id is returned with
known: false once all of it has arrived, and decoding resumes after it.
Noise that starts with an STX then costs up to a frame's length of the
bytes after it, as in the C library and pymavlink.
Every complete frame in bin, as {frames, errors, rest}. Errors are
collected, so a noisy line degrades instead of failing. Takes decode/3's
options.
Encode a frame to wire bytes. raw and known are ignored.
Errors:
{:unknown_msgid, id} | the dialect does not have id: a guessed crc_extra makes a frame the peer drops without a word |
{:out_of_range, field} | seq, compid or a flags byte outside 0..255, sysid or target_sysid outside 32 bits, or msgid outside 24 bits |
{:unsupported_incompat_flags, flags} | a bit in incompat_flags other than the three above |
:payload_too_long | the payload, after truncation, is longer than the message |
@spec iflag_signed() :: 1
@spec stx_v1() :: 254
@spec stx_v2() :: 253