diff --git a/lib/gpio.ex b/lib/gpio.ex index a6debea..da9df25 100644 --- a/lib/gpio.ex +++ b/lib/gpio.ex @@ -237,12 +237,15 @@ defmodule Circuits.GPIO do end @doc """ - Return dynamic configuration and status information about a GPIO + Return dynamic configuration and status information about a GPIO or handle - See `t:gpio_spec/0` for the ways of referring to GPIOs. If the GPIO is found, - this function returns information about the GPIO. + Pass a `t:gpio_spec/0` to query a GPIO without opening it, or a `t:Handle.t/0` + to query an open GPIO. If the GPIO is found, this function returns information + about the GPIO. Status for GPIO groups is not supported. """ - @spec status(gpio_spec()) :: {:ok, status()} | {:error, atom()} + @spec status(gpio_spec() | Handle.t()) :: {:ok, status()} | {:error, atom()} + def status(handle) when is_struct(handle), do: Handle.status(handle) + def status(gpio_spec) do {backend, backend_defaults} = default_backend() diff --git a/lib/gpio/cdev.ex b/lib/gpio/cdev.ex index 9f5fd93..4965379 100644 --- a/lib/gpio/cdev.ex +++ b/lib/gpio/cdev.ex @@ -28,7 +28,7 @@ defmodule Circuits.GPIO.CDev do alias Circuits.GPIO.Handle alias Circuits.GPIO.Nif - defstruct [:ref] + defstruct [:ref, :locations] @impl Backend def enumerate(options) do @@ -128,7 +128,8 @@ defmodule Circuits.GPIO.CDev do with {:ok, controller, offsets} <- resolve_group(specs, options), {:ok, ref} <- Nif.open(gpio_spec, {controller, offsets}, direction, value, pull_mode, drive_mode) do - {:ok, %__MODULE__{ref: ref}} + locations = Enum.map(offsets, &{controller, &1}) + {:ok, %__MODULE__{ref: ref, locations: locations}} end end @@ -173,6 +174,15 @@ defmodule Circuits.GPIO.CDev do Nif.read(ref) end + @impl Handle + def status(%Circuits.GPIO.CDev{locations: [location]}) do + Nif.status(location) + end + + def status(%Circuits.GPIO.CDev{}) do + {:error, :group_handle} + end + @impl Handle def write(%Circuits.GPIO.CDev{ref: ref}, value) do Nif.write(ref, value) diff --git a/lib/gpio/handle.ex b/lib/gpio/handle.ex index 1dd84c6..54e722d 100644 --- a/lib/gpio/handle.ex +++ b/lib/gpio/handle.ex @@ -16,6 +16,11 @@ defprotocol Circuits.GPIO.Handle do @spec read(t()) :: GPIO.value() def read(handle) + # Return dynamic GPIO configuration and status information. + @doc false + @spec status(t()) :: {:ok, GPIO.status()} | {:error, atom()} + def status(handle) + # Set the GPIO state. For a group, this is an integer with one bit per line. @doc false @spec write(t(), GPIO.value()) :: :ok diff --git a/test/circuits_gpio_test.exs b/test/circuits_gpio_test.exs index 361a915..dd36ec4 100644 --- a/test/circuits_gpio_test.exs +++ b/test/circuits_gpio_test.exs @@ -166,7 +166,7 @@ defmodule Circuits.GPIOTest do end end - describe "status/2" do + describe "status/1" do test "all gpio_spec examples" do expected = %{consumer: "", direction: :input, pull_mode: :none, drive_mode: :push_pull} @@ -215,6 +215,29 @@ defmodule Circuits.GPIOTest do GPIO.close(gpio) end + + test "status reports an open GPIO handle" do + {:ok, gpio} = GPIO.open({@gpiochip, 1}, :input, pull_mode: :pullup) + + assert GPIO.status(gpio) == + {:ok, + %{ + consumer: "stub", + direction: :input, + pull_mode: :pullup, + drive_mode: :push_pull + }} + + GPIO.close(gpio) + end + + test "status does not support GPIO groups" do + {:ok, gpio} = GPIO.open([{@gpiochip, 0}, {@gpiochip, 1}], :input) + + assert GPIO.status(gpio) == {:error, :group_handle} + + GPIO.close(gpio) + end end describe "drive_mode" do