Tested and working on a Raspberry Pi 4B with a Pi Sense Hat connected.

This commit is contained in:
James Harton 2019-12-30 20:37:34 +13:00
parent 33e332ea22
commit ba68653925
15 changed files with 375 additions and 32 deletions

164
.credo.exs Normal file
View file

@ -0,0 +1,164 @@
# This file contains the configuration for Credo and you are probably reading
# this after creating it with `mix credo.gen.config`.
#
# If you find anything wrong or unclear in this file, please report an
# issue on GitHub: https://github.com/rrrene/credo/issues
#
%{
#
# You can have as many configs as you like in the `configs:` field.
configs: [
%{
#
# Run any exec using `mix credo -C <name>`. If no exec name is given
# "default" is used.
#
name: "default",
#
# These are the files included in the analysis:
files: %{
#
# You can give explicit globs or simply directories.
# In the latter case `**/*.{ex,exs}` will be used.
#
included: ["lib/", "src/", "test/", "web/", "apps/"],
excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/"]
},
#
# Load and configure plugins here:
#
plugins: [],
#
# If you create your own checks, you must specify the source files for
# them here, so they can be loaded by Credo before running the analysis.
#
requires: [],
#
# If you want to enforce a style guide and need a more traditional linting
# experience, you can change `strict` to `true` below:
#
strict: false,
#
# If you want to use uncolored output by default, you can change `color`
# to `false` below:
#
color: true,
#
# You can customize the parameters of any check by adding a second element
# to the tuple.
#
# To disable a check put `false` as second element:
#
# {Credo.Check.Design.DuplicatedCode, false}
#
checks: [
#
## Consistency Checks
#
{Credo.Check.Consistency.ExceptionNames, []},
{Credo.Check.Consistency.LineEndings, []},
{Credo.Check.Consistency.ParameterPatternMatching, []},
{Credo.Check.Consistency.SpaceAroundOperators, false},
{Credo.Check.Consistency.SpaceInParentheses, []},
{Credo.Check.Consistency.TabsOrSpaces, []},
#
## Design Checks
#
# You can customize the priority of any check
# Priority values are: `low, normal, high, higher`
#
{Credo.Check.Design.AliasUsage,
[priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]},
# You can also customize the exit_status of each check.
# If you don't want TODO comments to cause `mix credo` to fail, just
# set this value to 0 (zero).
#
{Credo.Check.Design.TagTODO, [exit_status: 2]},
{Credo.Check.Design.TagFIXME, []},
#
## Readability Checks
#
{Credo.Check.Readability.AliasOrder, []},
{Credo.Check.Readability.FunctionNames, []},
{Credo.Check.Readability.LargeNumbers, []},
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]},
{Credo.Check.Readability.ModuleAttributeNames, []},
{Credo.Check.Readability.ModuleDoc, []},
{Credo.Check.Readability.ModuleNames, []},
{Credo.Check.Readability.ParenthesesInCondition, []},
{Credo.Check.Readability.ParenthesesOnZeroArityDefs, []},
{Credo.Check.Readability.PredicateFunctionNames, []},
{Credo.Check.Readability.PreferImplicitTry, []},
{Credo.Check.Readability.RedundantBlankLines, []},
{Credo.Check.Readability.Semicolons, []},
{Credo.Check.Readability.SpaceAfterCommas, []},
{Credo.Check.Readability.StringSigils, []},
{Credo.Check.Readability.TrailingBlankLine, []},
{Credo.Check.Readability.TrailingWhiteSpace, []},
# TODO: enable by default in Credo 1.1
{Credo.Check.Readability.UnnecessaryAliasExpansion, false},
{Credo.Check.Readability.VariableNames, []},
#
## Refactoring Opportunities
#
{Credo.Check.Refactor.CondStatements, []},
{Credo.Check.Refactor.CyclomaticComplexity, []},
{Credo.Check.Refactor.FunctionArity, []},
{Credo.Check.Refactor.LongQuoteBlocks, []},
{Credo.Check.Refactor.MapInto, []},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
{Credo.Check.Refactor.Nesting, []},
{Credo.Check.Refactor.UnlessWithElse, []},
{Credo.Check.Refactor.WithClauses, []},
#
## Warnings
#
{Credo.Check.Warning.BoolOperationOnSameValues, []},
{Credo.Check.Warning.ExpensiveEmptyEnumCheck, []},
{Credo.Check.Warning.IExPry, []},
{Credo.Check.Warning.IoInspect, []},
{Credo.Check.Warning.LazyLogging, []},
{Credo.Check.Warning.OperationOnSameValues, []},
{Credo.Check.Warning.OperationWithConstantResult, []},
{Credo.Check.Warning.RaiseInsideRescue, []},
{Credo.Check.Warning.UnusedEnumOperation, []},
{Credo.Check.Warning.UnusedFileOperation, []},
{Credo.Check.Warning.UnusedKeywordOperation, []},
{Credo.Check.Warning.UnusedListOperation, []},
{Credo.Check.Warning.UnusedPathOperation, []},
{Credo.Check.Warning.UnusedRegexOperation, []},
{Credo.Check.Warning.UnusedStringOperation, []},
{Credo.Check.Warning.UnusedTupleOperation, []},
#
# Controversial and experimental checks (opt-in, just replace `false` with `[]`)
#
{Credo.Check.Consistency.MultiAliasImportRequireUse, false},
{Credo.Check.Consistency.UnusedVariableNames, false},
{Credo.Check.Design.DuplicatedCode, false},
{Credo.Check.Readability.AliasAs, false},
{Credo.Check.Readability.MultiAlias, false},
{Credo.Check.Readability.Specs, false},
{Credo.Check.Readability.SinglePipe, false},
{Credo.Check.Refactor.ABCSize, false},
{Credo.Check.Refactor.AppendSingleItem, false},
{Credo.Check.Refactor.DoubleBooleanNegation, false},
{Credo.Check.Refactor.ModuleDependencies, false},
{Credo.Check.Refactor.PipeChainStart, false},
{Credo.Check.Refactor.VariableRebinding, false},
{Credo.Check.Warning.MapGetUnsafePass, false},
{Credo.Check.Warning.UnsafeToAtom, false}
#
# Custom checks can be created using `mix credo.gen.check`.
#
]
}
]
}

View file

@ -6,6 +6,43 @@ Wafer provides Elixir protocols for interacting with device registers and dealin
Wafer implements the [GPIO](https://hexdocs.pm/wafer/Wafer.GPIOProto.html) and [Chip](https://hexdocs.pm/wafer/Wafer.Chip.html) protocols for [ElixirALE](https://hex.pm/packages/elixir_ale)'s GPIO and I2C drivers, [Circuits.GPIO](https://hex.pm/packages/circuits_gpio) and [Circuits.I2C](https://hex.pm/packages/circuits_i2c). Implementing it for SPI should also be trivial, I just don't have any SPI devices to test with at the moment. Wafer implements the [GPIO](https://hexdocs.pm/wafer/Wafer.GPIOProto.html) and [Chip](https://hexdocs.pm/wafer/Wafer.Chip.html) protocols for [ElixirALE](https://hex.pm/packages/elixir_ale)'s GPIO and I2C drivers, [Circuits.GPIO](https://hex.pm/packages/circuits_gpio) and [Circuits.I2C](https://hex.pm/packages/circuits_i2c). Implementing it for SPI should also be trivial, I just don't have any SPI devices to test with at the moment.
## Working with registers
Wafer provides the very helpful [Registers](https://hexdocs.pm/wafer/Wafer.Registers.html) macros which allow you to quickly and easily define your registers for your device:
Here's a very simple example:
```elixir
defmodule HTS221.Registers do
use Wafer.Registers
defregister(:ctrl_reg1, 0x20, :rw, 1)
defregister(:humidity_out_l, 0x28, :ro, 1)
defregister(:humidity_out_h, 0x29, :ro, 1)
end
defmodule HTS221 do
import HTS221.Registers
use Bitwise
def humidity(conn) do
with {:ok, <<msb>>} <- read_humidity_out_h(conn),
{:ok, <<lsb>} <- read_humidity_out_l(conn),
do: {:ok, msb <<< 8 + lsb}
end
def on?(conn) do
case read_ctrl_reg1(conn) do
{:ok, <<1::integer-size(1), _::bits>>} -> true
_ -> false
end
end
def turn_on(conn), do: write_ctrl_reg1(conn, <<1::integer-size(1), 0::integer-size(7)>>)
def turn_off(conn), do: write_ctrl_reg1(conn, <<0>>)
end
```
## Installation ## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed If [available in Hex](https://hex.pm/docs/publish), the package can be installed

View file

@ -26,7 +26,8 @@ defmodule Wafer.Driver.CircuitsGPIO do
def acquire(opts) when is_list(opts) do def acquire(opts) when is_list(opts) do
with pin when is_pin_number(pin) <- Keyword.get(opts, :pin), with pin when is_pin_number(pin) <- Keyword.get(opts, :pin),
direction when is_pin_direction(direction) <- Keyword.get(opts, :direction, :out), direction when is_pin_direction(direction) <- Keyword.get(opts, :direction, :out),
{:ok, ref} <- Driver.open(pin, direction, Keyword.drop(opts, ~w[pin direction]a)) do pin_dir <- String.to_atom(Enum.join([direction, "put"], "")),
{:ok, ref} <- Driver.open(pin, pin_dir, Keyword.drop(opts, ~w[pin direction]a)) do
{:ok, %__MODULE__{ref: ref, pin: pin, direction: direction}} {:ok, %__MODULE__{ref: ref, pin: pin, direction: direction}}
else else
:error -> {:error, "Circuits.GPIO requires a `pin` option."} :error -> {:error, "Circuits.GPIO requires a `pin` option."}

View file

@ -83,7 +83,7 @@ defimpl Wafer.I2C, for: Wafer.Driver.ElixirALEI2C do
def read(%{pid: pid}, bytes, options \\ []) def read(%{pid: pid}, bytes, options \\ [])
when is_pid(pid) and is_byte_size(bytes) and is_list(options) do when is_pid(pid) and is_byte_size(bytes) and is_list(options) do
case Driver.read(pid, bytes, options) do case Driver.read(pid, bytes) do
data when is_binary(data) -> {:ok, data} data when is_binary(data) -> {:ok, data}
{:error, reason} -> {:error, reason} {:error, reason} -> {:error, reason}
end end
@ -91,7 +91,7 @@ defimpl Wafer.I2C, for: Wafer.Driver.ElixirALEI2C do
def write(%{pid: pid} = conn, data, options \\ []) def write(%{pid: pid} = conn, data, options \\ [])
when is_pid(pid) and is_binary(data) and is_list(options) do when is_pid(pid) and is_binary(data) and is_list(options) do
case Driver.write(pid, data, options) do case Driver.write(pid, data) do
:ok -> {:ok, conn} :ok -> {:ok, conn}
{:error, reason} -> {:error, reason} {:error, reason} -> {:error, reason}
end end
@ -99,7 +99,7 @@ defimpl Wafer.I2C, for: Wafer.Driver.ElixirALEI2C do
def write_read(%{pid: pid} = conn, data, bytes, options \\ []) def write_read(%{pid: pid} = conn, data, bytes, options \\ [])
when is_pid(pid) and is_binary(data) and is_byte_size(bytes) and is_list(options) do when is_pid(pid) and is_binary(data) and is_byte_size(bytes) and is_list(options) do
case Driver.write_read(pid, data, bytes, options) do case Driver.write_read(pid, data, bytes) do
data when is_binary(data) -> {:ok, data, conn} data when is_binary(data) -> {:ok, data, conn}
{:error, reason} -> {:error, reason} {:error, reason} -> {:error, reason}
end end

17
mix.exs
View file

@ -26,13 +26,20 @@ defmodule Wafer.MixProject do
[ [
{:mimic, "~> 1.1", only: :test}, {:mimic, "~> 1.1", only: :test},
{:credo, "~> 1.1", only: [:dev, :test], runtime: false}, {:credo, "~> 1.1", only: [:dev, :test], runtime: false},
{:elixir_ale, "~> 1.2", only: :dev, optional: true}, {:elixir_ale, "~> 1.2", optional: true},
{:circuits_i2c, "~> 0.3", only: :dev, optional: true}, {:circuits_i2c, "~> 0.3", optional: true},
{:circuits_gpio, "~> 0.4", only: :dev, optional: true}, {:circuits_gpio, "~> 0.4", optional: true},
{:circuits_spi, "~> 0.1", only: :dev, optional: true} {:circuits_spi, "~> 0.1", optional: true}
] ]
end end
defp elixirc_paths(:test), do: ["test/support" | elixirc_paths(nil)] # Load fake versions of the Circuits and ElixirALE modules unless explicitly
# told not to.
defp elixirc_paths(:test) do
if System.get_env("FAKE_DRIVERS") == "false",
do: elixirc_paths(nil),
else: ["test/support" | elixirc_paths(nil)]
end
defp elixirc_paths(_), do: ["lib"] defp elixirc_paths(_), do: ["lib"]
end end

View file

@ -0,0 +1,46 @@
defmodule WaferAcceptanceCircuitsI2CDeviceTest do
use ExUnit.Case, async: true
# Only run acceptance tests if the fake drivers are not loaded.
if System.get_env("FAKE_DRIVERS") == "false" do
alias Wafer.Driver.CircuitsI2C, as: Driver
defmodule HTS221 do
use Wafer.Registers
@moduledoc """
A not very useful driver for the HTS221 humidity sensor on the Pi Sense Hat.
"""
defregister(:who_am_i, 0x0F, :ro, 1)
defregister(:ctrl_reg1, 0x20, :rw, 1)
def on?(conn) do
case read_ctrl_reg1(conn) do
{:ok, <<1::integer-size(1), _::bits>>} -> true
_ -> false
end
end
def turn_on(conn), do: write_ctrl_reg1(conn, <<1::integer-size(1), 0::integer-size(7)>>)
def turn_off(conn), do: write_ctrl_reg1(conn, <<0>>)
end
describe "generated registers" do
test "reading" do
{:ok, conn} = Driver.acquire(bus_name: "i2c-1", address: 0x5F)
assert {:ok, <<0xBC>>} = HTS221.read_who_am_i(conn)
end
test "reading and writing" do
{:ok, conn} = Driver.acquire(bus_name: "i2c-1", address: 0x5F)
assert {:ok, conn} = HTS221.turn_on(conn)
assert HTS221.on?(conn) == true
assert {:ok, conn} = HTS221.turn_off(conn)
assert HTS221.on?(conn) == false
end
end
end
end

View file

@ -0,0 +1,46 @@
defmodule WaferAcceptanceElixirALEI2CDeviceTest do
use ExUnit.Case, async: true
# Only run acceptance tests if the fake drivers are not loaded.
if System.get_env("FAKE_DRIVERS") == "false" do
alias Wafer.Driver.ElixirALEI2C, as: Driver
defmodule LPS25H do
use Wafer.Registers
@moduledoc """
A not very useful driver for the LPS25H pressure senser on the Pi Sense Hat.
"""
defregister(:who_am_i, 0x0F, :ro, 1)
defregister(:ctrl_reg1, 0x20, :rw, 1)
def on?(conn) do
case read_ctrl_reg1(conn) do
{:ok, <<1::integer-size(1), _::integer-size(7)>>} -> true
_ -> false
end
end
def turn_on(conn), do: write_ctrl_reg1(conn, <<1::integer-size(1), 0::integer-size(7)>>)
def turn_off(conn), do: write_ctrl_reg1(conn, <<0>>)
end
describe "generated registers" do
test "reading" do
{:ok, conn} = Driver.acquire(bus_name: "i2c-1", address: 0x5C)
assert {:ok, <<0xBD>>} = LPS25H.read_who_am_i(conn)
end
test "reading and writing" do
{:ok, conn} = Driver.acquire(bus_name: "i2c-1", address: 0x5C)
assert {:ok, conn} = LPS25H.turn_on(conn)
assert LPS25H.on?(conn) == true
assert {:ok, conn} = LPS25H.turn_off(conn)
assert LPS25H.on?(conn) == false
end
end
end
end

View file

@ -65,6 +65,10 @@ defmodule WaferDriverCircuitsGPIODispatcherTest do
test "disabling rising interrupts" do test "disabling rising interrupts" do
conn = conn() conn = conn()
Driver
|> stub(:set_interrupts, fn _, _ -> :ok end)
Dispatcher.handle_call({:enable, conn, :rising, self()}, nil, state()) Dispatcher.handle_call({:enable, conn, :rising, self()}, nil, state())
assert {:reply, {:ok, conn}, _state} = assert {:reply, {:ok, conn}, _state} =
@ -75,6 +79,10 @@ defmodule WaferDriverCircuitsGPIODispatcherTest do
test "disabling falling interrupts" do test "disabling falling interrupts" do
conn = conn() conn = conn()
Driver
|> stub(:set_interrupts, fn _, _ -> :ok end)
Dispatcher.handle_call({:enable, conn, :falling, self()}, nil, state()) Dispatcher.handle_call({:enable, conn, :falling, self()}, nil, state())
assert {:reply, {:ok, conn}, _state} = assert {:reply, {:ok, conn}, _state} =
@ -85,6 +93,10 @@ defmodule WaferDriverCircuitsGPIODispatcherTest do
test "disabling both interrupts" do test "disabling both interrupts" do
conn = conn() conn = conn()
Driver
|> stub(:set_interrupts, fn _, _ -> :ok end)
Dispatcher.handle_call({:enable, conn, :both, self()}, nil, state()) Dispatcher.handle_call({:enable, conn, :both, self()}, nil, state())
assert {:reply, {:ok, conn}, _state} = assert {:reply, {:ok, conn}, _state} =
@ -97,6 +109,9 @@ defmodule WaferDriverCircuitsGPIODispatcherTest do
describe "handle_info/2" do describe "handle_info/2" do
test "publishing interrupts when the value was previously unknown" do test "publishing interrupts when the value was previously unknown" do
Driver
|> stub(:set_interrupts, fn _, _ -> :ok end)
{:reply, {:ok, conn}, state} = {:reply, {:ok, conn}, state} =
Dispatcher.handle_call({:enable, conn(), :both, self()}, nil, state()) Dispatcher.handle_call({:enable, conn(), :both, self()}, nil, state())
@ -106,6 +121,9 @@ defmodule WaferDriverCircuitsGPIODispatcherTest do
end end
test "publishing interrupts when the value rises" do test "publishing interrupts when the value rises" do
Driver
|> stub(:set_interrupts, fn _, _ -> :ok end)
state = state(values: %{1 => 0}) state = state(values: %{1 => 0})
{:reply, {:ok, conn}, state} = {:reply, {:ok, conn}, state} =
@ -117,6 +135,9 @@ defmodule WaferDriverCircuitsGPIODispatcherTest do
end end
test "publishing interrupts when the value falls" do test "publishing interrupts when the value falls" do
Driver
|> stub(:set_interrupts, fn _, _ -> :ok end)
state = state(values: %{1 => 1}) state = state(values: %{1 => 1})
{:reply, {:ok, conn}, state} = {:reply, {:ok, conn}, state} =
@ -128,6 +149,9 @@ defmodule WaferDriverCircuitsGPIODispatcherTest do
end end
test "ignoring interrupts when the value stays high" do test "ignoring interrupts when the value stays high" do
Driver
|> stub(:set_interrupts, fn _, _ -> :ok end)
state = state(values: %{1 => 1}) state = state(values: %{1 => 1})
{:reply, {:ok, _conn}, state} = {:reply, {:ok, _conn}, state} =
@ -139,6 +163,9 @@ defmodule WaferDriverCircuitsGPIODispatcherTest do
end end
test "ignoring interrupts when the value stays low" do test "ignoring interrupts when the value stays low" do
Driver
|> stub(:set_interrupts, fn _, _ -> :ok end)
state = state(values: %{1 => 0}) state = state(values: %{1 => 0})
{:reply, {:ok, _conn}, state} = {:reply, {:ok, _conn}, state} =

View file

@ -12,7 +12,7 @@ defmodule WaferDriverCircuitsGPIOTest do
Driver Driver
|> expect(:open, 1, fn pin, direction, opts -> |> expect(:open, 1, fn pin, direction, opts ->
assert pin == 1 assert pin == 1
assert direction == :out assert direction == :output
assert opts == [] assert opts == []
{:ok, :erlang.make_ref()} {:ok, :erlang.make_ref()}
end) end)
@ -132,5 +132,7 @@ defmodule WaferDriverCircuitsGPIOTest do
end end
end end
defp conn, do: %Subject{ref: :erlang.make_ref(), pin: 1, direction: :out} defp conn(opts \\ []), do: struct(%Subject{pin: pin(), ref: :erlang.make_ref()}, opts)
defp pin, do: 1
end end

View file

@ -65,6 +65,10 @@ defmodule WaferDriverElixirALEGPIODispatcherTest do
test "disabling rising interrupts" do test "disabling rising interrupts" do
conn = conn() conn = conn()
Driver
|> stub(:set_int, fn _, _ -> :ok end)
Dispatcher.handle_call({:enable, conn, :rising, self()}, nil, state()) Dispatcher.handle_call({:enable, conn, :rising, self()}, nil, state())
assert {:reply, {:ok, conn}, _state} = assert {:reply, {:ok, conn}, _state} =
@ -75,6 +79,10 @@ defmodule WaferDriverElixirALEGPIODispatcherTest do
test "disabling falling interrupts" do test "disabling falling interrupts" do
conn = conn() conn = conn()
Driver
|> stub(:set_int, fn _, _ -> :ok end)
Dispatcher.handle_call({:enable, conn, :falling, self()}, nil, state()) Dispatcher.handle_call({:enable, conn, :falling, self()}, nil, state())
assert {:reply, {:ok, conn}, _state} = assert {:reply, {:ok, conn}, _state} =
@ -85,6 +93,10 @@ defmodule WaferDriverElixirALEGPIODispatcherTest do
test "disabling both interrupts" do test "disabling both interrupts" do
conn = conn() conn = conn()
Driver
|> stub(:set_int, fn _, _ -> :ok end)
Dispatcher.handle_call({:enable, conn, :both, self()}, nil, state()) Dispatcher.handle_call({:enable, conn, :both, self()}, nil, state())
assert {:reply, {:ok, conn}, _state} = assert {:reply, {:ok, conn}, _state} =
@ -97,6 +109,9 @@ defmodule WaferDriverElixirALEGPIODispatcherTest do
describe "handle_info/2" do describe "handle_info/2" do
test "publishing rising interrupts" do test "publishing rising interrupts" do
Driver
|> stub(:set_int, fn _, _ -> :ok end)
{:reply, {:ok, conn}, state} = {:reply, {:ok, conn}, state} =
Dispatcher.handle_call({:enable, conn(), :both, self()}, nil, state()) Dispatcher.handle_call({:enable, conn(), :both, self()}, nil, state())
@ -106,6 +121,9 @@ defmodule WaferDriverElixirALEGPIODispatcherTest do
end end
test "publishing falling interrupts" do test "publishing falling interrupts" do
Driver
|> stub(:set_int, fn _, _ -> :ok end)
{:reply, {:ok, conn}, state} = {:reply, {:ok, conn}, state} =
Dispatcher.handle_call({:enable, conn(), :both, self()}, nil, state()) Dispatcher.handle_call({:enable, conn(), :both, self()}, nil, state())

View file

@ -106,5 +106,6 @@ defmodule WaferDriverElixirALEGPIOTest do
end end
end end
defp conn, do: %Subject{pid: self(), pin: 1, direction: :out} defp conn(opts \\ []), do: struct(%Subject{pin: pin(), pid: self()}, opts)
defp pin, do: 1
end end

View file

@ -140,10 +140,9 @@ defmodule WaferElixirALEI2CTest do
conn = conn() conn = conn()
Driver Driver
|> expect(:read, 1, fn pid, bytes, opts -> |> expect(:read, 1, fn pid, bytes ->
assert pid == conn.pid assert pid == conn.pid
assert bytes == 2 assert bytes == 2
assert opts == []
<<0, 0>> <<0, 0>>
end) end)
@ -156,10 +155,9 @@ defmodule WaferElixirALEI2CTest do
conn = conn() conn = conn()
Driver Driver
|> expect(:write, 1, fn pid, data, opts -> |> expect(:write, 1, fn pid, data ->
assert pid == conn.pid assert pid == conn.pid
assert data == <<0, 0>> assert data == <<0, 0>>
assert opts == []
:ok :ok
end) end)
@ -172,11 +170,10 @@ defmodule WaferElixirALEI2CTest do
conn = conn() conn = conn()
Driver Driver
|> expect(:write_read, 1, fn pid, data, bytes, opts -> |> expect(:write_read, 1, fn pid, data, bytes ->
assert pid == conn.pid assert pid == conn.pid
assert data == <<1>> assert data == <<1>>
assert bytes == 2 assert bytes == 2
assert opts == []
<<0, 0>> <<0, 0>>
end) end)

View file

@ -138,7 +138,7 @@ defmodule WaferRegistersTest do
end end
defp test_mod do defp test_mod do
mod = TestUtils.random_module_name() mod = random_module_name()
defmodule mod do defmodule mod do
use Wafer.Registers use Wafer.Registers
@ -150,4 +150,13 @@ defmodule WaferRegistersTest do
mod mod
end end
defp random_module_name do
name =
16
|> :crypto.strong_rand_bytes()
|> Base.encode64(padding: false)
Module.concat(__MODULE__, name)
end
end end

View file

@ -7,7 +7,7 @@ defmodule Circuits.GPIO do
do: :ok do: :ok
def open(pin_number, pin_direction, options \\ []) def open(pin_number, pin_direction, options \\ [])
when is_pin_number(pin_number) and is_pin_direction(pin_direction) and is_list(options), when is_pin_number(pin_number) and pin_direction in ~w[input output]a and is_list(options),
do: {:ok, :erlang.make_ref()} do: {:ok, :erlang.make_ref()}
def close(ref) when is_reference(ref), do: :ok def close(ref) when is_reference(ref), do: :ok

View file

@ -1,12 +0,0 @@
defmodule TestUtils do
@moduledoc false
def random_module_name do
name =
16
|> :crypto.strong_rand_bytes()
|> Base.encode64(padding: false)
Module.concat(__MODULE__, name)
end
end