Skip to content

Commit 9cc1ecb

Browse files
committed
Defer loading the NIF until opening an I2C bus
This change moves the NIF load from the time at which the module is loaded to the time when I2C actually is used. The primary motivation for doing this is to defer native code crashes from happening at load time to the time of first use. Load time is harder to debug and sometimes its not clear which NIF caused the crash. The calls to `apply` get around some complexity with ignoring Dialyzer warnings. Dialyzer can't figure out that the recursive looking call actually invokes the NIF code.
1 parent f75eef8 commit 9cc1ecb

File tree

1 file changed

+12
-18
lines changed

1 file changed

+12
-18
lines changed

lib/i2c/i2c_nif.ex

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,27 @@
11
defmodule Circuits.I2C.Nif do
2-
@on_load {:load_nif, 0}
3-
@compile {:autoload, false}
4-
52
@moduledoc false
63

7-
def load_nif() do
8-
# Only load the NIF if using supported backends
9-
load? =
10-
case Application.get_env(:circuits_i2c, :default_backend) do
11-
Circuits.I2C.I2CDev -> true
12-
{Circuits.I2C.I2CDev, _} -> true
13-
_ -> false
14-
end
4+
defp load_nif() do
5+
nif_binary = Application.app_dir(:circuits_i2c, "priv/i2c_nif")
6+
:erlang.load_nif(to_charlist(nif_binary), 0)
7+
end
158

16-
if load? do
17-
nif_binary = Application.app_dir(:circuits_i2c, "priv/i2c_nif")
18-
:erlang.load_nif(to_charlist(nif_binary), 0)
19-
else
20-
:ok
9+
def open(device) do
10+
with :ok <- load_nif() do
11+
apply(__MODULE__, :open, [device])
2112
end
2213
end
2314

24-
def open(_device), do: :erlang.nif_error(:nif_not_loaded)
2515
def read(_ref, _address, _count, _retries), do: :erlang.nif_error(:nif_not_loaded)
2616
def write(_ref, _address, _data, _retries), do: :erlang.nif_error(:nif_not_loaded)
2717

2818
def write_read(_ref, _address, _write_data, _read_count, _retries),
2919
do: :erlang.nif_error(:nif_not_loaded)
3020

3121
def close(_ref), do: :erlang.nif_error(:nif_not_loaded)
32-
def info(), do: :erlang.nif_error(:nif_not_loaded)
22+
23+
def info() do
24+
:ok = load_nif()
25+
apply(__MODULE__, :info, [])
26+
end
3327
end

0 commit comments

Comments
 (0)