MAVLink2.Frame (mavlink2 v0.1.0)

Copy Markdown View Source

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 only

Incompat flags

Bit
0x01SIGNEDa signature follows the checksum; see MAVLink2.Signing
0x02SYSID32sysid is 4 bytes. encode/2 sets it when sysid is over 255
0x04TARGET32the 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

Functions

Decode the first complete frame in bin.

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.

Types

t()

@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

decode(bin, dialect, opts \\ [])

@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; keep bin
  • {:error, reason, rest}: resynchronise from rest

Option unknown: is :skip (the default) or :keep, for an id the dialect lacks.

Errors:

Resumes
:no_stxat the next STX, so a run of junk is one error
:mavlink_v1_unsupportedafter 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_checksumafter 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.

drain(bin, dialect, opts \\ [])

@spec drain(binary(), module(), keyword()) :: {[t()], [term()], binary()}

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(f, dialect)

@spec encode(t(), module()) :: {:ok, binary()} | {:error, term()}

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_longthe payload, after truncation, is longer than the message

iflag_signed()

@spec iflag_signed() :: 1

stx_v1()

@spec stx_v1() :: 254

stx_v2()

@spec stx_v2() :: 253