XMAVLink.Router (xmavlink v0.14.3)

Copy Markdown View Source

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

Delivery metadata returned by send_message/1..3.

Represents the state of the XMAVLink.Router. Initial values should be set in config.exs.

t()

Functions

Send a MAVLink message to one or more recipients using available connections. For now if destination is unreachable it will log a warning

Synchronously pack, route, and send a MAVLink message.

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

connection_key()

@type connection_key() ::
  :local
  | binary()
  | port()
  | {port(), XMAVLink.Types.net_address(), XMAVLink.Types.net_port()}

delivery()

@type delivery() :: %{
  source_connection: connection_key(),
  recipients: [connection_key()],
  remote_recipients: [connection_key()],
  target: XMAVLink.Dialect.target() | nil,
  message_id: XMAVLink.Types.message_id(),
  unreachable?: boolean()
}

Delivery metadata returned by send_message/1..3.

router_name()

@type router_name() :: atom() | {:global, term()} | {:via, module(), term()}

router_ref()

@type router_ref() :: GenServer.server()

subscribe_query()

@type subscribe_query() :: [
  {:message, XMAVLink.Message.t() | :unknown}
  | {subscribe_query_id_key(), 0..255}
  | {:as_frame, boolean()}
]

subscribe_query_id_key()

@type subscribe_query_id_key() ::
  :source_system | :source_component | :target_system | :target_component

t()

@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

pack_and_send(message)

@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_system and :source_component override 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
    }
  )

pack_and_send(router, message)

@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}

pack_and_send(router, message, opts)

@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}

pack_and_send(router, message, version, opts)

@spec pack_and_send(
  router_ref(),
  XMAVLink.Message.t(),
  XMAVLink.Types.version(),
  keyword()
) ::
  :ok | {:error, :protocol_undefined}

send_message(message)

@spec send_message(XMAVLink.Message.t()) :: {:ok, delivery()} | {:error, term()}

Synchronously pack, route, and send a MAVLink message.

This is the structured alternative to pack_and_send/2..4. Pass :version in opts to select MAVLink 1 or 2, and pass :source_system plus :source_component to override the router's local identity for this message.

The success reply includes the selected recipient connection keys. Connection keys are internal runtime identifiers, but they are useful for observability and tests.

send_message(message, opts)

@spec send_message(
  XMAVLink.Message.t(),
  keyword()
) :: {:ok, delivery()} | {:error, term()}
@spec send_message(router_ref(), XMAVLink.Message.t()) ::
  {:ok, delivery()} | {:error, term()}

send_message(router, message, opts)

@spec send_message(router_ref(), XMAVLink.Message.t(), keyword()) ::
  {:ok, delivery()} | {:error, term()}

start_link(args, opts \\ [])

@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 dialect
  • system: The System id of this system 1..255, typically low for vehicles and high for

                    ground stations
  • component: 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 :name to register

                    a non-default router, or `name: nil` in the args map to
                    start an unregistered router addressed by pid.

subscribe()

@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

subscribe(router)

@spec subscribe(router_ref() | subscribe_query()) :: :ok | {:error, :invalid_message}

subscribe(router, query)

@spec subscribe(router_ref(), subscribe_query()) :: :ok | {:error, :invalid_message}

unsubscribe()

@spec unsubscribe() :: :ok

Un-subscribes calling process from all existing subscriptions

Example

  XMAVLink.Router.unsubscribe

unsubscribe(router)

@spec unsubscribe(router_ref()) :: :ok