MAVLink2.Link (mavlink2 v0.1.0)

Copy Markdown View Source

A MAVLink link over one transport: it owns the transport, reassembles frames from the byte stream, numbers what it sends and delivers each decoded frame to its subscribers as {MAVLink2.Link, link, frame}, where link is the link's name or pid.

It knows framing and sequence numbers, not what a message means.

  • A partial frame stays buffered until the rest arrives.
  • Decode errors are counted in stats/1, not raised: a noisy line degrades.
  • Outgoing frames are numbered per link; a gap in a sender's numbers (per system and component id) is counted as :dropped.

Options:

:dialecta MAVLink2.Dialect (required)
:transporta MAVLink2.Transport (default MAVLink2.Transport.UART); the rest of the options go to its open/1
:sendablethe message ids the peer accepts; others are refused with {:error, {:not_sendable, id}}. Default: any id the dialect has
:sysid, :compidthis end's ids (default 1, 1): sysid from 1 to 32 bits, compid 1 to 255. 0 is the broadcast id and never a sender's, so the link refuses it, here and in send_message/4
:unknown:skip (default) or :keep: deliver frames whose id the dialect lacks, unchecked, with known: false (see MAVLink2.Frame.decode/3). Each is counted in :unknown as well as :rx
:signinga MAVLink2.Signing: every frame sent is signed, and a frame received is delivered only if it verifies (counted as :unsigned, :bad_signature or :replay otherwise, and delivered tagged to subscribers that ask; see subscribe/3). Without it, frames are sent unsigned and every frame received is delivered, signed or not
:clockUnix time in microseconds for signing timestamps (default System.os_time(:microsecond))
:nameregistered name

A transport that does not open logs a warning and the link returns :ignore, so a board without the peer still starts.

Summary

Functions

Returns a specification to start this module under a supervisor.

Writes a decoded frame's raw bytes unchanged: its sequence number, source and signature are the original sender's. For routing; :sendable does not apply. A link with :signing does not sign what it forwards.

This end's :sysid, :compid and :dialect.

Encodes message, a struct of the link's dialect, and sends it. target_system over 255 goes in the header (TARGET32) with 255 in the payload, as MAVLink requires. Options are send_message/4's other than :target_sysid. Raises ArgumentError for a struct that is not of the link's dialect, or a field value that does not fit its type.

Sends message msgid with payload. sysid: and compid: override the link's; target_sysid: puts a target system in the header, for a target over 255 (with 255 in the payload's target_system); force: true sends an id outside :sendable, for probing.

Starts a link. Raises ArgumentError for an unknown option or a bad value; see the module doc for the options.

Counts: :rx, :tx, :errors, :dropped, :unknown, :unsigned, :bad_signature, :replay.

Delivers every frame the link receives to pid as {MAVLink2.Link, link, frame}, frame a MAVLink2.Frame. Subscribing again replaces the options. The subscription ends when pid exits.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

forward(link, frame)

@spec forward(GenServer.server(), MAVLink2.Frame.t()) :: :ok | {:error, term()}

Writes a decoded frame's raw bytes unchanged: its sequence number, source and signature are the original sender's. For routing; :sendable does not apply. A link with :signing does not sign what it forwards.

info(link)

@spec info(GenServer.server()) :: %{
  sysid: non_neg_integer(),
  compid: 0..255,
  dialect: module()
}

This end's :sysid, :compid and :dialect.

send(link, message, opts \\ [])

@spec send(GenServer.server(), struct(), keyword()) :: :ok | {:error, term()}

Encodes message, a struct of the link's dialect, and sends it. target_system over 255 goes in the header (TARGET32) with 255 in the payload, as MAVLink requires. Options are send_message/4's other than :target_sysid. Raises ArgumentError for a struct that is not of the link's dialect, or a field value that does not fit its type.

MAVLink2.Link.send(link, %MyDialect.Heartbeat{type: 6, autopilot: 8})

send_message(link, msgid, payload, opts \\ [])

@spec send_message(GenServer.server(), non_neg_integer(), binary(), keyword()) ::
  :ok | {:error, term()}

Sends message msgid with payload. sysid: and compid: override the link's; target_sysid: puts a target system in the header, for a target over 255 (with 255 in the payload's target_system); force: true sends an id outside :sendable, for probing.

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Starts a link. Raises ArgumentError for an unknown option or a bad value; see the module doc for the options.

MAVLink2.Link.start_link(dialect: MyDialect, device: "/dev/ttyACM0", speed: 115_200)

stats(link)

@spec stats(GenServer.server()) :: %{required(atom()) => non_neg_integer()}

Counts: :rx, :tx, :errors, :dropped, :unknown, :unsigned, :bad_signature, :replay.

subscribe(link, pid \\ self(), opts \\ [])

@spec subscribe(GenServer.server(), pid(), keyword()) :: :ok

Delivers every frame the link receives to pid as {MAVLink2.Link, link, frame}, frame a MAVLink2.Frame. Subscribing again replaces the options. The subscription ends when pid exits.

Options:

decode: truedeliver {MAVLink2.Link, link, frame, message} instead, message the decoded struct (a dialect from MAVLink2.Dialect.XML). Frames the dialect cannot decode are not delivered
only: [...]deliver only these messages: message structs' modules (MyDialect.Heartbeat) or ids
rejected: truealso deliver frames the link's :signing refuses, as {MAVLink2.Link, link, {:rejected, reason, frame}}, reason one of :unsigned, :bad_signature, :replay, so that one cannot be mistaken for a verified frame. Its timestamp moves nothing. A router forwards these; an application can show them as untrusted
:ok = MAVLink2.Link.subscribe(link, self(), decode: true, only: [MyDialect.Heartbeat])

receive do
  {MAVLink2.Link, ^link, frame, %MyDialect.Heartbeat{} = heartbeat} -> {frame.sysid, heartbeat}
end

unsubscribe(link, pid \\ self())

@spec unsubscribe(GenServer.server(), pid()) :: :ok