defmodule Drone.Adapters.Tello.Connection do
@moduledoc """
UDP connection handler for the Tello drone.
Manages a `:gen_udp` socket for sending commands and receiving
responses from a Tello drone over Wi-Fi.
"""
@default_drone_ip {192, 168, 10, 1}
@default_drone_port 8889
@default_local_port 8889
@default_timeout 10_000
def default_drone_ip, do: @default_drone_ip
def default_drone_port, do: @default_drone_port
def default_local_port, do: @default_local_port
def default_timeout, do: @default_timeout
@spec open(keyword()) :: {:ok, port()} | {:error, term()}
def open(opts \\ []) do
local_port = Keyword.get(opts, :local_port, @default_local_port)
:gen_udp.open(local_port, [:inet, {:active, false}])
end
@spec close(port()) :: :ok
def close(socket) do
:gen_udp.close(socket)
end
@spec send_command(port(), String.t(), keyword()) :: {:ok, term()} | {:error, term()}
def send_command(socket, command, opts \\ []) do
ip = Keyword.get(opts, :drone_ip, @default_drone_ip)
port = Keyword.get(opts, :drone_port, @default_drone_port)
timeout = Keyword.get(opts, :timeout, @default_timeout)
case :gen_udp.send(socket, ip, port, command) do
:ok ->
receive_response(socket, timeout)
{:error, reason} ->
{:error, reason}
end
end
@spec receive_response(port(), non_neg_integer()) :: {:ok, binary()} | {:error, term()}
def receive_response(socket, timeout) do
case :gen_udp.recv(socket, 0, timeout) do
{:ok, {_ip, _port, data}} when is_binary(data) ->
{:ok, data}
{:ok, {_ip, _port, data}} when is_list(data) ->
{:ok, :erlang.list_to_binary(data)}
{:error, :timeout} ->
{:error, :timeout}
{:error, reason} ->
{:error, reason}
end
end
end