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:
:dialect | a MAVLink2.Dialect (required) |
:transport | a MAVLink2.Transport (default MAVLink2.Transport.UART); the rest of the options go to its open/1 |
:sendable | the message ids the peer accepts; others are refused with {:error, {:not_sendable, id}}. Default: any id the dialect has |
:sysid, :compid | this 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 |
:signing | a 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 |
:clock | Unix time in microseconds for signing timestamps (default System.os_time(:microsecond)) |
:name | registered 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
Returns a specification to start this module under a supervisor.
See Supervisor.
@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.
@spec info(GenServer.server()) :: %{ sysid: non_neg_integer(), compid: 0..255, dialect: module() }
This end's :sysid, :compid and :dialect.
@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})
@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.
@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)
@spec stats(GenServer.server()) :: %{required(atom()) => non_neg_integer()}
Counts: :rx, :tx, :errors, :dropped, :unknown, :unsigned, :bad_signature, :replay.
@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: true | deliver {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: true | also 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
@spec unsubscribe(GenServer.server(), pid()) :: :ok