diff --git a/lib/wafer/drivers/circuits/gpio.ex b/lib/wafer/drivers/circuits/gpio.ex index e2b9288..b39521b 100644 --- a/lib/wafer/drivers/circuits/gpio.ex +++ b/lib/wafer/drivers/circuits/gpio.ex @@ -57,11 +57,11 @@ defimpl Wafer.GPIO, for: Wafer.Driver.Circuits.GPIO do import Wafer.Guards def read(%{ref: ref}) when is_reference(ref) do - case(Wrapper.read(ref)) do + case Wrapper.read(ref) do value when is_pin_value(value) -> {:ok, value} - {:error, reason} -> {:error, reason} - other -> {:error, "Invalid response from driver: #{inspect(other)}"} end + rescue + error -> {:error, error} end def write(%{ref: ref} = conn, value) when is_reference(ref) and is_pin_value(value) do @@ -80,11 +80,11 @@ defimpl Wafer.GPIO, for: Wafer.Driver.Circuits.GPIO do def enable_interrupt(conn, pin_condition, metadata \\ nil) when is_pin_condition(pin_condition) do - with :ok <- Dispatcher.enable(conn, pin_condition, metadata), do: {:ok, conn} + Dispatcher.enable(conn, pin_condition, metadata) end def disable_interrupt(conn, pin_condition) when is_pin_condition(pin_condition) do - with :ok <- Dispatcher.disable(conn, pin_condition), do: {:ok, conn} + Dispatcher.disable(conn, pin_condition) end def pull_mode(%{ref: ref} = conn, mode) when is_reference(ref) and is_pin_pull_mode(mode) do diff --git a/lib/wafer/drivers/circuits/i2c.ex b/lib/wafer/drivers/circuits/i2c.ex index 6699ea6..c08cf7d 100644 --- a/lib/wafer/drivers/circuits/i2c.ex +++ b/lib/wafer/drivers/circuits/i2c.ex @@ -1,7 +1,7 @@ defmodule Wafer.Driver.Circuits.I2C do - defstruct ~w[address bus ref]a + defstruct ~w[address bus conn]a @behaviour Wafer.Conn - alias Circuits.I2C.I2CDev + alias Circuits.I2C.Bus alias Wafer.Driver.Circuits.I2C.Wrapper alias Wafer.I2C import Wafer.Guards @@ -12,7 +12,7 @@ defmodule Wafer.Driver.Circuits.I2C do Implements the `Wafer.Conn` behaviour as well as the `Wafer.Chip` and `Wafer.I2C` protocols. """ - @type t :: %__MODULE__{address: I2C.address(), bus: binary, ref: reference} + @type t :: %__MODULE__{address: I2C.address(), bus: binary, conn: Bus.t()} @type options :: [option] @type option :: {:bus_name, binary} | {:address, I2C.address()} | {:force, boolean} @@ -24,10 +24,10 @@ defmodule Wafer.Driver.Circuits.I2C do def acquire(opts) when is_list(opts) do with {:ok, bus} when is_binary(bus) <- Keyword.fetch(opts, :bus_name), {:ok, address} when is_i2c_address(address) <- Keyword.fetch(opts, :address), - {:ok, ref} when is_reference(ref) or is_struct(ref, I2CDev) <- Wrapper.open(bus), - devices when is_list(devices) <- Wrapper.detect_devices(ref), + {:ok, conn} <- Wrapper.open(bus), + devices when is_list(devices) <- Wrapper.detect_devices(conn), true <- Keyword.get(opts, :force, false) || Enum.member?(devices, address) do - {:ok, %__MODULE__{bus: bus, address: address, ref: ref}} + {:ok, %__MODULE__{bus: bus, address: address, conn: conn}} else false -> {:error, "No device detected at address. Pass `force: true` to override."} @@ -49,24 +49,24 @@ defimpl Wafer.Release, for: Wafer.Driver.Circuits.I2C do Release all resources associated with this device. """ @spec release(I2C.t()) :: :ok | {:error, reason :: any} - def release(%I2C{ref: ref} = _conn), do: Wrapper.close(ref) + def release(%I2C{conn: conn} = _conn), do: Wrapper.close(conn) end defimpl Wafer.Chip, for: Wafer.Driver.Circuits.I2C do alias Wafer.Driver.Circuits.I2C.Wrapper import Wafer.Guards - def read_register(%{ref: ref, address: address}, register_address, bytes) + def read_register(%{conn: conn, address: address}, register_address, bytes) when is_i2c_address(address) and is_register_address(register_address) and is_byte_size(bytes), - do: Wrapper.write_read(ref, address, <>, bytes) + do: Wrapper.write_read(conn, address, <>, bytes) def read_register(_conn, _register_address, _bytes), do: {:error, "Invalid argument"} - def write_register(%{ref: ref, address: address} = conn, register_address, data) + def write_register(%{conn: inner, address: address} = conn, register_address, data) when is_i2c_address(address) and is_register_address(register_address) and is_binary(data) do - with :ok <- Wrapper.write(ref, address, <>), do: {:ok, conn} + with :ok <- Wrapper.write(inner, address, <>), do: {:ok, conn} end def write_register(_conn, _register_address, _data), do: {:error, "Invalid argument"} @@ -86,36 +86,35 @@ defimpl Wafer.I2C, for: Wafer.Driver.Circuits.I2C do import Wafer.Guards alias Wafer.Driver.Circuits.I2C.Wrapper - def read(%{ref: ref, address: address}, bytes, options \\ []) + def read(%{conn: conn, address: address}, bytes, options \\ []) when is_i2c_address(address) and is_byte_size(bytes) and is_list(options) do - case Wrapper.read(ref, address, bytes, options) do + case Wrapper.read(conn, address, bytes, options) do {:ok, data} when is_binary(data) and byte_size(data) == bytes -> {:ok, data} {:error, reason} -> {:error, reason} other -> {:error, "Invalid response from driver: #{inspect(other)}"} end end - def write(%{ref: ref, address: address} = conn, data, options \\ []) + def write(%{conn: inner, address: address} = conn, data, options \\ []) when is_i2c_address(address) and is_binary(data) and is_list(options) do - with :ok <- Wrapper.write(ref, address, data, options), do: {:ok, conn} + with :ok <- Wrapper.write(inner, address, data, options), do: {:ok, conn} end - def write_read(%{ref: ref, address: address} = conn, data, bytes, options \\ []) + def write_read(%{conn: inner, address: address} = conn, data, bytes, options \\ []) when is_i2c_address(address) and is_binary(data) and is_byte_size(bytes) and is_list(options) do - case Wrapper.write_read(ref, address, data, bytes, options) do + case Wrapper.write_read(inner, address, data, bytes, options) do {:ok, data} when is_binary(data) and byte_size(data) == bytes -> {:ok, data, conn} {:error, reason} -> {:error, reason} other -> {:error, "Invalid response from driver: #{inspect(other)}"} end end - def detect_devices(%{ref: ref}) when is_reference(ref) do - case Wrapper.detect_devices(ref) do + def detect_devices(%{conn: conn}) do + case Wrapper.detect_devices(conn) do devices when is_list(devices) -> {:ok, devices} {:error, reason} -> {:error, reason} - other -> {:error, "Invalid response from driver: #{inspect(other)}"} end end end diff --git a/lib/wafer/drivers/elixir_ale/i2c.ex b/lib/wafer/drivers/elixir_ale/i2c.ex index 271a578..8edc1c8 100644 --- a/lib/wafer/drivers/elixir_ale/i2c.ex +++ b/lib/wafer/drivers/elixir_ale/i2c.ex @@ -115,7 +115,6 @@ defimpl Wafer.I2C, for: Wafer.Driver.ElixirALE.I2C do case Wrapper.detect_devices(pid) do devices when is_list(devices) -> {:ok, devices} {:error, reason} -> {:error, reason} - other -> {:error, "Invalid response from driver: #{inspect(other)}"} end end end diff --git a/lib/wafer/drivers/fake.ex b/lib/wafer/drivers/fake.ex index b91374e..8b243f3 100644 --- a/lib/wafer/drivers/fake.ex +++ b/lib/wafer/drivers/fake.ex @@ -87,7 +87,7 @@ defimpl Wafer.I2C, for: Wafer.Driver.Fake do {:ok, <<0::size(bits)>>, conn} end - def detect_devices(_conn), do: [] + def detect_devices(_conn), do: {:ok, []} end defimpl Wafer.SPI, for: Wafer.Driver.Fake do diff --git a/lib/wafer/i2c.ex b/lib/wafer/i2c.ex index 0bceb7c..4961ecd 100644 --- a/lib/wafer/i2c.ex +++ b/lib/wafer/i2c.ex @@ -63,7 +63,7 @@ defprotocol Wafer.I2C do @doc """ Detect the devices adjacent to the connection's device on the same I2C bus. """ - @spec detect_devices(Conn.t()) :: {:ok, [address]} + @spec detect_devices(Conn.t()) :: {:ok, [address]} | {:error, any} def detect_devices(conn) end diff --git a/lib/wafer/release.ex b/lib/wafer/release.ex index 77dd796..724355e 100644 --- a/lib/wafer/release.ex +++ b/lib/wafer/release.ex @@ -30,7 +30,7 @@ defprotocol Wafer.Release do Release all resources associated with the connection. Usually in preparation for shutdown. """ - @spec release(Conn.t()) :: :ok + @spec release(Conn.t()) :: :ok | {:error, any} def release(conn) end diff --git a/lib/wafer/twiddles.ex b/lib/wafer/twiddles.ex index 529ed24..1256616 100644 --- a/lib/wafer/twiddles.ex +++ b/lib/wafer/twiddles.ex @@ -173,7 +173,7 @@ defmodule Wafer.Twiddles do iex> find_ones(<<0x0A>>) [1, 3] """ - @spec find_ones(byte | single_byte_binary) :: non_neg_integer + @spec find_ones(byte | single_byte_binary) :: [non_neg_integer] def find_ones(byte) when is_byte(byte) do 0..7 |> Enum.filter(&(get_bit(byte, &1) == 1)) @@ -192,7 +192,7 @@ defmodule Wafer.Twiddles do iex> find_zeroes(<<0xFA>>) [0, 2] """ - @spec find_zeroes(byte | single_byte_binary) :: non_neg_integer + @spec find_zeroes(byte | single_byte_binary) :: [non_neg_integer] def find_zeroes(byte) when is_byte(byte) do 0..7 |> Enum.filter(&(get_bit(byte, &1) == 0)) diff --git a/mix.exs b/mix.exs index 02208d3..1d7c5dc 100644 --- a/mix.exs +++ b/mix.exs @@ -56,6 +56,7 @@ defmodule Wafer.MixProject do # Dev/test {:credo, "~> 1.6", devtest}, + {:dialyxir, "~> 1.4", devtest}, {:earmark, "~> 1.4", devtest}, {:ex_check, "~> 0.15", devtest}, {:ex_doc, ">= 0.0.0", devtest}, diff --git a/mix.lock b/mix.lock index cb12569..ecb9156 100644 --- a/mix.lock +++ b/mix.lock @@ -1,13 +1,15 @@ %{ "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "circuits_gpio": {:hex, :circuits_gpio, "1.0.0", "b2a493b1822ec712bfba7068a016930f6db5e31713b9b84ed8bc307c7c323682", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "da64c1d9ba1329cd7ca7e63adcd68d73e2294d6b48eb66c9a1064f3db5c523f3"}, - "circuits_i2c": {:hex, :circuits_i2c, "2.0.0", "8343b12879189f844835abeaf31a36c5626b8ace58413a582794fdfe60c2dc0e", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "06eccd33b36bcedf41730cac8da58e359967ea63a2cd899cea58c2a138634cc4"}, + "circuits_i2c": {:hex, :circuits_i2c, "2.0.1", "e9ab22f078b403cafd2c5006fff448f9a790f73c04e9135b7ac22f45f2e63c5c", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "a1567004389b49637fe34d9dd8bdf36c26a53c269e654753860b5c09532bc3c4"}, "circuits_spi": {:hex, :circuits_spi, "1.3.0", "d66d4c8818739416958cea1d846d66896ab7c28fa42695f1cae3c2c7a3e9e9ca", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "56e49b346fdd43185832a03d3de3751c2ce9928ee3ce4a31a364f6548fe2b74c"}, "credo": {:hex, :credo, "1.7.1", "6e26bbcc9e22eefbff7e43188e69924e78818e2fe6282487d0703652bc20fd62", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e9871c6095a4c0381c89b6aa98bc6260a8ba6addccf7f6a53da8849c748a58a2"}, + "dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"}, "earmark": {:hex, :earmark, "1.4.19", "3854a17305c880cc46305af15fb1630568d23a709aba21aaa996ced082fc29d7", [:mix], [{:earmark_parser, ">= 1.4.18", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "d5a8c9f9e37159a8fdd3ea8437fb4e229eaf56d5129b9a011dc4780a4872079d"}, "earmark_parser": {:hex, :earmark_parser, "1.4.19", "de0d033d5ff9fc396a24eadc2fcf2afa3d120841eb3f1004d138cbf9273210e8", [:mix], [], "hexpm", "527ab6630b5c75c3a3960b75844c314ec305c76d9899bb30f71cb85952a9dc45"}, "elixir_ale": {:hex, :elixir_ale, "1.2.1", "07ac2f17a0191b8bd3b0df6b526c7f699a3a4d690c9def573fcb5824eef24d98", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "bfb099137500a3b8c4a1750cf07f2d704897ef9feac3412064bf9edc7d74193c"}, "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"}, + "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "ex_check": {:hex, :ex_check, "0.15.0", "074b94c02de11c37bba1ca82ae5cc4926e6ccee862e57a485b6ba60fca2d8dc1", [:mix], [], "hexpm", "33848031a0c7e4209c3b4369ce154019788b5219956220c35ca5474299fb6a0e"}, "ex_doc": {:hex, :ex_doc, "0.28.1", "34fab7e7201c5a1f275f3b2f837125c940c512e8543d181bd4dd7acb19c8dba0", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "10e564dd59101a5edc4de7009a54baed015a246dee01f7200aab24e8f57fc044"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, diff --git a/test/drivers/circuits_gpio_test.exs b/test/drivers/circuits_gpio_test.exs index 43e42d9..2ab4dd8 100644 --- a/test/drivers/circuits_gpio_test.exs +++ b/test/drivers/circuits_gpio_test.exs @@ -101,7 +101,7 @@ defmodule WaferDriverCircuits.GPIOTest do |> expect(:enable, 1, fn conn1, pin_condition, _metadata -> assert conn1 == conn assert pin_condition == :rising - :ok + {:ok, conn1} end) assert {:ok, ^conn} = GPIO.enable_interrupt(conn, :rising) @@ -116,7 +116,7 @@ defmodule WaferDriverCircuits.GPIOTest do |> expect(:disable, 1, fn conn1, pin_condition -> assert conn1 == conn assert pin_condition == :rising - :ok + {:ok, conn1} end) assert {:ok, ^conn} = GPIO.disable_interrupt(conn, :rising) diff --git a/test/drivers/circuits_i2c_test.exs b/test/drivers/circuits_i2c_test.exs index 85dd95e..8bfc624 100644 --- a/test/drivers/circuits_i2c_test.exs +++ b/test/drivers/circuits_i2c_test.exs @@ -77,7 +77,7 @@ defmodule WaferCircuits.I2CTest do Wrapper |> expect(:close, 1, fn ref -> - assert ref == conn.ref + assert ref == conn.conn :ok end) @@ -91,7 +91,7 @@ defmodule WaferCircuits.I2CTest do Wrapper |> expect(:write_read, 1, fn ref, addr, data, bytes -> - assert ref == conn.ref + assert ref == conn.conn assert addr == conn.address assert data == <<0>> assert bytes == 2 @@ -108,7 +108,7 @@ defmodule WaferCircuits.I2CTest do Wrapper |> expect(:write, 1, fn ref, addr, data -> - assert ref == conn.ref + assert ref == conn.conn assert addr == conn.address assert data == <<1, 2, 3>> :ok @@ -124,7 +124,7 @@ defmodule WaferCircuits.I2CTest do Wrapper |> expect(:write_read, 1, fn ref, addr, data, bytes -> - assert ref == conn.ref + assert ref == conn.conn assert addr == conn.address assert data == <<0>> assert bytes == 2 @@ -133,7 +133,7 @@ defmodule WaferCircuits.I2CTest do Wrapper |> expect(:write, 1, fn ref, addr, data -> - assert ref == conn.ref + assert ref == conn.conn assert addr == conn.address assert data == <<0, 1, 1>> :ok @@ -149,7 +149,7 @@ defmodule WaferCircuits.I2CTest do Wrapper |> expect(:read, 1, fn ref, addr, bytes, opts -> - assert ref == conn.ref + assert ref == conn.conn assert addr == conn.address assert bytes == 2 assert opts == [] @@ -166,7 +166,7 @@ defmodule WaferCircuits.I2CTest do Wrapper |> expect(:write, 1, fn ref, addr, data, opts -> - assert ref == conn.ref + assert ref == conn.conn assert addr == conn.address assert data == <<0, 0>> assert opts == [] @@ -183,7 +183,7 @@ defmodule WaferCircuits.I2CTest do Wrapper |> expect(:write_read, 1, fn ref, addr, data, bytes, opts -> - assert ref == conn.ref + assert ref == conn.conn assert addr == conn.address assert data == <<1>> assert bytes == 2 @@ -202,7 +202,7 @@ defmodule WaferCircuits.I2CTest do Wrapper |> expect(:detect_devices, 1, fn ref -> - assert conn.ref == ref + assert conn.conn == ref [conn.address] end) @@ -210,5 +210,5 @@ defmodule WaferCircuits.I2CTest do end end - defp conn, do: %Subject{ref: :erlang.make_ref(), bus: "i2c-1", address: 0x13} + defp conn, do: %Subject{conn: :erlang.make_ref(), bus: "i2c-1", address: 0x13} end