Connect to serial, udp and tcp ports and listen for, validate and forward MAVLink messages towards their destinations on other connections and/or Elixir processes subscribing to messages.
The rules for MAVLink packet forwarding are described here:
https://mavlink.io/en/guide/routing.html
and here:
http://ardupilot.org/dev/docs/mavlink-routing-in-ardupilot.html
Summary
Types
Represents the state of the XMAVLink.Router. Initial values should be set in config.exs.
Functions
Send a MAVLink message to one or more recipients using available connections. For now if destination is unreachable it will log a warning
Start the MAVLink Router service. You should not call this directly, use the MAVLink application to start this under a supervision tree with the services it expects to use.
Subscribes the calling process to MAVLink messages from the installed dialect matching the query.
Un-subscribes calling process from all existing subscriptions
Types
@type connection_key() :: :local | binary() | port() | {port(), XMAVLink.Types.net_address(), XMAVLink.Types.net_port()}
@type mavlink_address() :: XMAVLink.Types.mavlink_address()
Represents the state of the XMAVLink.Router. Initial values should be set in config.exs.
Fields
dialect: The XMAVLink dialect module generated by mix mavlink from a MAVLink definition file
connection_strings: Configuration strings describing the network and serial connections MAVLink messages
are to be received and sent over. Allowed formats are: ```udpin:<local ip>:<local port> udpout:<remote ip>:<remote port> tcpout:<remote ip>:<remote port> serial:<device>:<baud rate>``` Note there is no tcpin connection - tcp is rarely used for MAVLink, the exception being SITL testing which requires a tcpout connection.connections: A map containing the state of the connections described by connection_strings along
with the local connection, which is automatically created and responsible for allowing Elixir processes to receive and send MAVLink messages. The map is keyed by the port, device or :local to allow the corresponding connection state to be easily retrieved when we receive a message. See MAVLink.*Connection for map values. Note LocalConnection contains the system/component id, subscriber list and next sequence number.routes: A map from a {system id, component id} tuple to the connection key a message from that
system/component was last received on. Used to forward messages to that system/component.system_time_boot_ms:
A map from a {system id, component id} tuple to the last SYSTEM_TIME.time_boot_ms seen from that source. Used to clear stale learned routes when a remote system reboots.
@type mavlink_connection() :: XMAVLink.Types.connection()
@type router_ref() :: GenServer.server()
@type subscribe_query() :: [ {:message, XMAVLink.Message.t() | :unknown} | {subscribe_query_id_key(), 0..255} | {:as_frame, boolean()} ]
@type subscribe_query_id_key() ::
:source_system | :source_component | :target_system | :target_component
@type t() :: %XMAVLink.Router{ connection_retry_ms: non_neg_integer(), connection_strings: [String.t()], connection_supervisor: pid() | nil, connection_worker_monitors: %{required(reference()) => pid()}, connection_workers: %{required(connection_key()) => pid()}, connections: %{required(connection_key()) => mavlink_connection()}, dialect: module() | nil, name: router_name() | nil, remote_forwarding: boolean(), routes: %{required(mavlink_address()) => connection_key()}, signing: XMAVLink.Signing.t() | nil, subscription_cache: router_name() | nil, system_time_boot_ms: %{required(mavlink_address()) => non_neg_integer()} }
Functions
@spec pack_and_send(XMAVLink.Message.t()) :: :ok | {:error, :protocol_undefined}
Send a MAVLink message to one or more recipients using available connections. For now if destination is unreachable it will log a warning
Parameters
- router: Optional router name or pid. Defaults to
XMAVLink.Router. - message: A MAVLink message structure from the installed dialect
- version: Force sending using a specific MAVLink protocol (default 2)
- opts: Optional send settings:
:source_systemand:source_componentoverride the router's configured local identity for this message. Provide both or neither.
Example
XMAVLink.Router.pack_and_send(
%Common.RcChannelsOverride{
target_system: 1,
target_component: 1,
chan1_raw: 1500,
chan2_raw: 1500,
chan3_raw: 1500,
chan4_raw: 1500,
chan5_raw: 1500,
chan6_raw: 1500,
chan7_raw: 1500,
chan8_raw: 1500,
chan9_raw: 0,
chan10_raw: 0,
chan11_raw: 0,
chan12_raw: 0,
chan13_raw: 0,
chan14_raw: 0,
chan15_raw: 0,
chan16_raw: 0,
chan17_raw: 0,
chan18_raw: 0
}
)
@spec pack_and_send(router_ref(), XMAVLink.Message.t()) :: :ok | {:error, :protocol_undefined}
@spec pack_and_send(XMAVLink.Message.t(), XMAVLink.Types.version() | keyword()) :: :ok | {:error, :protocol_undefined}
@spec pack_and_send( router_ref(), XMAVLink.Message.t(), XMAVLink.Types.version() | keyword() ) :: :ok | {:error, :protocol_undefined}
@spec pack_and_send(XMAVLink.Message.t(), XMAVLink.Types.version(), keyword()) :: :ok | {:error, :protocol_undefined}
@spec pack_and_send( router_ref(), XMAVLink.Message.t(), XMAVLink.Types.version(), keyword() ) :: :ok | {:error, :protocol_undefined}
@spec start_link( %{ :system => 1..255, :component => 1..255, :dialect => module(), optional(:name) => router_name() | nil, optional(:connection_strings) => [String.t()], optional(:connections) => [String.t()], optional(:connection_retry_ms) => non_neg_integer(), optional(:remote_forwarding) => boolean(), optional(:signing) => keyword() | nil }, [{atom(), any()}] ) :: {:ok, pid()}
Start the MAVLink Router service. You should not call this directly, use the MAVLink application to start this under a supervision tree with the services it expects to use.
Parameters
dialect: Name of the module generated by mix mavlink task to represent the enumerations
and messages of a particular MAVLink dialectsystem: The System id of this system 1..255, typically low for vehicles and high for
ground stationscomponent: The component id of this system 1..255, typically 1 for the autopilot
connection_strings: A list of strings in the following formats:
udpin:<local ip>:<local port> udpout:<remote ip>:<remote port> tcpout:<remote ip>:<remote port> serial:<device>:<baud rate>connection_retry_ms:
Retry delay for configured connection workers after open failures or TCP/serial disconnects. Defaults to 1000 ms.remote_forwarding:
Whether frames received from remote links are forwarded to other remote links. Defaults to true. Set false for endpoint/GCS use cases that should receive remote traffic locally without bridging it between links.opts: Standard GenServer options. Pass
:nameto registera non-default router, or `name: nil` in the args map to start an unregistered router addressed by pid.
@spec subscribe() :: :ok | {:error, :invalid_message}
Subscribes the calling process to MAVLink messages from the installed dialect matching the query.
Parameters
router: Optional router name or pid. Defaults to
XMAVLink.Router.query: Keyword list of zero or more of the following query keywords:
message: message_module | :unknown (use latter with as_frame) source_system: integer 0..255 source_component: integer 0..255 target_system: integer 0..255 target_component: integer 0..255 as_frame: true|false (default false, shows entire message frame with sender/target details)
Example
XMAVLink.Router.subscribe message: XMAVLink.Message.Heartbeat, source_system: 1
@spec subscribe(router_ref() | subscribe_query()) :: :ok | {:error, :invalid_message}
@spec subscribe(router_ref(), subscribe_query()) :: :ok | {:error, :invalid_message}
@spec unsubscribe() :: :ok
Un-subscribes calling process from all existing subscriptions
Example
XMAVLink.Router.unsubscribe
@spec unsubscribe(router_ref()) :: :ok