defmodule Drone.Adapter do
@moduledoc """
Behaviour definition for drone adapters.
Every drone adapter must implement this behaviour. The adapter is responsible
for all communication with the physical (or simulated) drone. The `Drone.Vehicle`
GenServer calls adapter callbacks, passing in opaque adapter state.
## Implementing an Adapter
defmodule Drone.Adapters.MyDrone do
@behaviour Drone.Adapter
@impl Drone.Adapter
def connect(opts) do
{:ok, %{ip: Keyword.fetch!(opts, :ip), port: Keyword.get(opts, :port, 8889)}}
end
@impl Drone.Adapter
def command(state, %Drone.Command{type: :takeoff}) do
{:ok, :ok, state}
end
@impl Drone.Adapter
def telemetry(state) do
{:ok, %{x: 0, y: 0, z: 30}, state}
end
@impl Drone.Adapter
def disconnect(_state) do
:ok
end
end
See `docs/adapter_authoring.md` for a complete guide.
"""
@type state :: term()
@callback connect(opts :: keyword()) ::
{:ok, state()}
| {:error, term()}
@callback command(state :: state(), command :: Drone.Command.t()) ::
{:ok, reply :: term(), new_state :: state()}
| {:error, reason :: term(), new_state :: state()}
@callback telemetry(state :: state()) ::
{:ok, map(), state()}
| {:error, term(), state()}
@callback disconnect(state :: state()) :: :ok
@optional_callbacks [disconnect: 1]
@doc """
Returns the adapter module for a given adapter identifier.
Accepts an atom (`:sim`, `:tello`) or a module directly.
"""
@spec resolve(atom() | module()) :: {:ok, module()} | {:error, :unknown_adapter}
def resolve(:sim), do: {:ok, Drone.Adapters.Sim}
def resolve(:tello), do: {:ok, Drone.Adapters.Tello}
def resolve(module) when is_atom(module), do: {:ok, module}
def resolve(_), do: {:error, :unknown_adapter}
end