Packages

An elixir library for MAVLink, an application that enables communication with other systems using the MAVLink protocol over serial, UDP and TCP connections, and utility modules for performing common MAVLink commands and tasks with one or more remote vehicles.

Current section

Files

Jump to
xmavlink lib mavlink tcp_out_connection.ex
Raw

lib/mavlink/tcp_out_connection.ex

defmodule XMAVLink.TCPOutConnection do
@moduledoc """
MAVLink.Router delegate for TCP connections
Typically used to connect to SITL on port 5760
"""
@smallest_mavlink_message 8
require Logger
alias XMAVLink.Frame
import XMAVLink.Frame, only: [binary_to_frame_and_tail: 1, validate_and_unpack: 2]
defstruct socket: nil, address: nil, port: nil, buffer: <<>>
@type t :: %XMAVLink.TCPOutConnection{
socket: pid,
address: XMAVLink.Types.net_address(),
port: XMAVLink.Types.net_port(),
buffer: binary
}
def handle_info(
{:tcp, socket, raw},
receiving_connection = %XMAVLink.TCPOutConnection{buffer: buffer},
dialect
) do
case binary_to_frame_and_tail(buffer <> raw) do
:not_a_frame ->
# Noise or malformed frame
if byte_size(buffer) + byte_size(raw) > 0 do
:ok =
Logger.debug("TCPOutConnection.handle_info: Not a frame #{inspect(buffer <> raw)}")
end
{:error, :not_a_frame, socket, struct(receiving_connection, buffer: <<>>)}
{nil, rest} ->
{:error, :incomplete_frame, socket, struct(receiving_connection, buffer: rest)}
{received_frame, rest} ->
# Rest could be a message, return later to try emptying the buffer
if byte_size(rest) >= @smallest_mavlink_message, do: send(self(), {:tcp, socket, <<>>})
case validate_and_unpack(received_frame, dialect) do
{:ok, valid_frame} ->
{:ok, socket, struct(receiving_connection, buffer: rest), valid_frame}
:unknown_message ->
# We re-broadcast valid frames with unknown messages
:ok =
Logger.debug("rebroadcasting unknown message with id #{received_frame.message_id}}")
{:ok, socket, struct(receiving_connection, buffer: rest),
struct(received_frame, target: :broadcast)}
reason ->
:ok =
Logger.debug(
"TCPOutConnection.handle_info: frame received failed: #{Atom.to_string(reason)}"
)
{:error, reason, socket, struct(receiving_connection, buffer: rest)}
end
end
end
def connect(["tcpout", address, port], controlling_process) do
case :gen_tcp.connect(address, port, [:binary, active: true]) do
{:ok, socket} ->
:ok = Logger.debug("Opened tcpout:#{Enum.join(Tuple.to_list(address), ".")}:#{port}")
send(
controlling_process,
{
:add_connection,
socket,
struct(
XMAVLink.TCPOutConnection,
socket: socket,
address: address,
port: port
)
}
)
:gen_tcp.controlling_process(socket, controlling_process)
other ->
:ok =
Logger.debug(
"Could not open tcpout:#{Enum.join(Tuple.to_list(address), ".")}:#{port}: #{inspect(other)}. Retrying in 1 second"
)
:timer.sleep(1000)
connect(["tcpout", address, port], controlling_process)
end
end
def forward(
%XMAVLink.TCPOutConnection{socket: socket},
%Frame{version: 1, mavlink_1_raw: packet}
) do
:gen_udp.send(socket, packet)
end
def forward(
%XMAVLink.TCPOutConnection{socket: socket},
%Frame{version: 2, mavlink_2_raw: packet}
) do
:gen_udp.send(socket, packet)
end
end