Packages

Wafer is an Elixir library to make writing drivers for i2c and SPI connected peripherals and interacting with GPIO pins easier.

Current section

Files

Jump to
wafer lib wafer drivers elixir_ale gpio.ex
Raw

lib/wafer/drivers/elixir_ale/gpio.ex

defmodule Wafer.Driver.ElixirALE.GPIO do
defstruct ~w[direction pid pin]a
@behaviour Wafer.Conn
alias Wafer.Driver.ElixirALE.GPIO.Wrapper
alias Wafer.GPIO
import Wafer.Guards
@moduledoc """
A connection to a native GPIO pin via ElixirALE's GPIO driver.
Implements the `Wafer.Conn` behaviour as well as the `Wafer.GPIO` protocol.
"""
@type t :: %__MODULE__{pid: pid}
@type options :: [option]
@type option :: {:pin, non_neg_integer} | {:direction, GPIO.pin_direction()} | {:force, boolean}
@doc """
Acquire a connection to the specified GPIO pin using the ElixirALE GPIO driver.
## Options
- `:pin` (required) - the integer pin number. Hardware dependent.
- `:direction` - either `:in` or `:out`. Defaults to `:out`.
"""
@spec acquire(options) :: {:ok, t} | {:error, reason :: any}
def acquire(opts) when is_list(opts) do
with {:ok, pin} when is_pin_number(pin) <- Keyword.fetch(opts, :pin),
direction when direction in [:in, :out] <- Keyword.get(opts, :direction, :out),
direction <- String.to_atom("#{direction}put"),
{:ok, pid} <- Wrapper.start_link(pin, direction, Keyword.drop(opts, ~w[pin direction]a)) do
{:ok, %__MODULE__{pid: pid, pin: pin, direction: direction}}
else
:error -> {:error, "ElixirALE.GPIO requires a `pin` option."}
{:error, reason} -> {:error, reason}
end
end
end
defimpl Wafer.Release, for: Wafer.Driver.ElixirALE.GPIO do
alias Wafer.Driver.ElixirALE.GPIO.Wrapper
alias Wafer.Driver.ElixirALE.GPIO
@doc """
Release all resources related to this GPIO pin connection.
Note that other connections may still be using the pin.
"""
@spec release(GPIO.t()) :: :ok | {:error, reason :: any}
def release(%GPIO{pid: pid} = _conn), do: Wrapper.release(pid)
end
defimpl Wafer.GPIO, for: Wafer.Driver.ElixirALE.GPIO do
alias Wafer.Driver.ElixirALE.GPIO.Wrapper
alias Wafer.Driver.ElixirALE.GPIO.Dispatcher
import Wafer.Guards
def read(%{pid: pid} = _conn) do
case Wrapper.read(pid) do
value when is_pin_value(value) -> {:ok, value}
{:error, reason} -> {:error, reason}
other -> {:error, "Invalid response from driver: #{inspect(other)}"}
end
end
def write(%{pid: pid} = conn, value) when is_pid(pid) and is_pin_value(value) do
with :ok <- Wrapper.write(pid, value), do: {:ok, conn}
end
def direction(_conn, _direction), do: {:error, :not_supported}
def enable_interrupt(conn, pin_condition, metadata \\ nil),
do: Dispatcher.enable(conn, pin_condition, metadata)
def disable_interrupt(conn, pin_condition),
do: Dispatcher.disable(conn, pin_condition)
def pull_mode(_conn, _pull_mode), do: {:error, :not_supported}
end
defimpl Wafer.DeviceID, for: Wafer.Driver.ElixirALE.GPIO do
def id(%{pin: pin}), do: {Wafer.Driver.ElixirALE.GPIO, pin}
end