diff --git a/.circleci/config.yml b/.circleci/config.yml index 6aef7f9..8532454 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 latest: &latest - pattern: "^1.14.2-erlang-25.*$" + pattern: "^1.15.7-erlang-26.*$" jobs: build-test: @@ -53,7 +53,8 @@ workflows: matrix: parameters: tag: [ - 1.14.2-erlang-25.2-alpine-3.17.0, + 1.15.7-erlang-26.1.2-alpine-3.18.4, + 1.14.4-erlang-25.3.2-alpine-3.17.3, 1.13.4-erlang-24.3.4-alpine-3.15.3, 1.12.3-erlang-24.3.4-alpine-3.15.3, 1.11.4-erlang-23.3.4.13-alpine-3.15.3, diff --git a/README.md b/README.md index afef6ea..7fd2744 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,10 @@ `Circuits.I2C` lets you communicate with hardware devices using the I2C protocol. +*This is the v1 maintenance branch. This is the version is well used in +production and still maintained. For Circuits.I2C v2, see the [circuits_i2c main +branch](https://github.com/elixir-circuits/circuits_i2c)* + If you're coming from Elixir/ALE, check out our [porting guide](PORTING.md). ## Getting started @@ -162,7 +166,7 @@ Please share other examples if you have them. No. This only runs on Linux-based boards. If you're interested in controlling an Arduino from a computer that can run Elixir, check out -[nerves_uart](https://hex.pm/packages/nerves_uart) for communicating via the +[circuits_uart](https://hex.pm/packages/circuits_uart) for communicating via the Arduino's serial connection or [firmata](https://github.com/mobileoverlord/firmata) for communication using the Arduino's Firmata protocol. diff --git a/c_src/i2c_nif.c b/c_src/i2c_nif.c index 72d0176..26cb89c 100644 --- a/c_src/i2c_nif.c +++ b/c_src/i2c_nif.c @@ -116,6 +116,8 @@ struct I2cNifPriv { static ERL_NIF_TERM atom_ok; static ERL_NIF_TERM atom_error; static ERL_NIF_TERM atom_nak; +static ERL_NIF_TERM atom_timeout; +static ERL_NIF_TERM atom_retry; static void i2c_dtor(ErlNifEnv *env, void *obj) { @@ -152,6 +154,8 @@ static int i2c_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM info) atom_ok = enif_make_atom(env, "ok"); atom_error = enif_make_atom(env, "error"); atom_nak = enif_make_atom(env, "i2c_nak"); + atom_timeout = enif_make_atom(env, "timeout"); + atom_retry = enif_make_atom(env, "retry"); *priv_data = priv; return 0; @@ -173,10 +177,24 @@ static ERL_NIF_TERM enif_make_errno_error(ErlNifEnv *env) reason = atom_nak; break; #endif + case ETIMEDOUT: + // I2C bus hung. On some platforms, Linux can try to recover it. + reason = atom_timeout; + break; + + case EAGAIN: + // I2C bus hung and an attempt is being made to recover it. + reason = atom_retry; + break; + case ENOENT: reason = enif_make_atom(env, "bus_not_found"); break; + case EOPNOTSUPP: + reason = enif_make_atom(env, "not_supported"); + break; + default: // strerror isn't usually that helpful, so if these // errors happen, please report or update this code diff --git a/lib/i2c/i2c_nif.ex b/lib/i2c/i2c_nif.ex index 3d00cbe..134683f 100644 --- a/lib/i2c/i2c_nif.ex +++ b/lib/i2c/i2c_nif.ex @@ -1,15 +1,17 @@ defmodule Circuits.I2C.Nif do - @on_load {:load_nif, 0} - @compile {:autoload, false} - @moduledoc false - def load_nif() do + defp load_nif() do nif_binary = Application.app_dir(:circuits_i2c, "priv/i2c_nif") :erlang.load_nif(to_charlist(nif_binary), 0) end - def open(_device), do: :erlang.nif_error(:nif_not_loaded) + def open(device) do + with :ok <- load_nif() do + apply(__MODULE__, :open, [device]) + end + end + def flags(_ref), do: :erlang.nif_error(:nif_not_loaded) def read(_ref, _address, _count, _retries), do: :erlang.nif_error(:nif_not_loaded) def write(_ref, _address, _data, _retries), do: :erlang.nif_error(:nif_not_loaded) @@ -18,5 +20,9 @@ defmodule Circuits.I2C.Nif do do: :erlang.nif_error(:nif_not_loaded) def close(_ref), do: :erlang.nif_error(:nif_not_loaded) - def info(), do: :erlang.nif_error(:nif_not_loaded) + + def info() do + :ok = load_nif() + apply(__MODULE__, :info, []) + end end diff --git a/mix.lock b/mix.lock index abc0984..ec35fb5 100644 --- a/mix.lock +++ b/mix.lock @@ -2,14 +2,14 @@ "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [: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", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"}, "dialyxir": {:hex, :dialyxir, "1.3.0", "fd1672f0922b7648ff9ce7b1b26fcf0ef56dda964a459892ad15f6b4410b5284", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "00b2a4bcd6aa8db9dcb0b38c1225b7277dca9bc370b6438715667071a304696f"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.32", "fa739a0ecfa34493de19426681b23f6814573faee95dfd4b4aafe15a7b5b32c6", [:mix], [], "hexpm", "b8b0dd77d60373e77a3d7e8afa598f325e49e8663a51bcc2b88ef41838cca755"}, - "elixir_make": {:hex, :elixir_make, "0.7.6", "67716309dc5d43e16b5abbd00c01b8df6a0c2ab54a8f595468035a50189f9169", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5a0569756b0f7873a77687800c164cca6dfc03a09418e6fcf853d78991f49940"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"}, + "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_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [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", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"}, + "ex_doc": {:hex, :ex_doc, "0.30.4", "e8395c8e3c007321abb30a334f9f7c0858d80949af298302daf77553468c0c39", [:mix], [{:earmark_parser, "~> 1.4.31", [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", "9a19f0c50ffaa02435668f5242f2b2a61d46b541ebf326884505dfd3dd7af5e4"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, + "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, }