aboutsummaryrefslogtreecommitdiff
path: root/src/gpio.erl
blob: 99da9be75c3a268ec5415673e5a10e9f258e67e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
%%% @author Guido Günther <agx@sigxcpu.org>
%%% @copyright (C) 2016, Guido Günther
%%% @doc
%%% Read and write GPIO values from userspace
%%%
%%% @reference https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
%%% @end
%%% License: LGLv3
-module(gpio).

-export([export/1,
         get_exported/0,
         get_direction/1,
         read/1,
         set_direction/2,
         unexport/1,
         write/2]).

-define(GPIO_BASE, "/sys/class/gpio/").
-define(GPIO_EXPORT, ?GPIO_BASE ++ "export").
-define(GPIO_UNEXPORT, ?GPIO_BASE ++ "unexport").

-type direction() :: in | out | low | high.
-type pin() :: pos_integer().

% @doc: write to GPIO pin
-spec write(Pin::pin(), 0 | 1) -> ok | {error, any()}.
write(Pin, Value) ->
    Sysfs = pin_sysfs_path(Pin, value),
    Out = io_lib:format("~p", [Value]),
    file:write_file(Sysfs, Out).

% @doc: read from GPIO pin
-spec read(Pin::pin()) -> {ok, 0 | 1} | {error, atom()}.
read(Pin) ->
    Sysfs = pin_sysfs_path(Pin, value),
    {ok, Data} = file:read_file(Sysfs),
    case Data of
        <<"0">> -> {ok, 0};
        <<"1">> -> {ok, 1};
        _-> {error, badval}
    end.

% @doc: export GPIO pin
-spec export(Pin::pin()) -> ok | {error, any()}.
export(Pin) ->
    Out = io_lib:format("~p", [Pin]),
    file:write_file(?GPIO_EXPORT, Out).

% @doc: get list of exported GPIO pins
-spec get_exported() -> {ok, list(pin())}.
get_exported() ->
    {ok, Files} = file:list_dir(?GPIO_BASE),
    {ok, R} = re:compile("^gpio[0-9]+$"),
    PinNames = [ X || X <- Files, nomatch /= re:run(X, R)],
    {ok, [ Num || {Num, []} <-
      [ string:to_integer(lists:nthtail(4, Pin)) || Pin <- PinNames ]]}.

% @doc: unexport GPIO pin
-spec unexport(Pin::pin()) -> ok | {error, any()}.
unexport(Pin) ->
    Out = io_lib:format("~p", [Pin]),
    file:write_file(?GPIO_UNEXPORT, Out).

% @doc: set GPIO pin direction
-spec set_direction(Pin::pin(), D::direction()) -> ok | {error, any()}.
set_direction(Pin, D) ->
    Sysfs = pin_sysfs_path(Pin, direction),
    Out = io_lib:format("~p", [D]),
    file:write_file(Sysfs, Out).

% @doc: get GPIO pin direction
-spec get_direction(Pin::pin()) -> {ok, direction()} | {error, any()}.
get_direction(Pin) ->
    Sysfs = pin_sysfs_path(Pin, direction),
    {ok, Data} = file:read_file(Sysfs),
    {ok, list_to_atom(string:strip(binary:bin_to_list(Data), right, $\n))}.

%% Private functions
-spec pin_sysfs_path(Pin::pin(), atom() | binary()) -> string().
pin_sysfs_path(Pin, File) ->
    io_lib:format(?GPIO_BASE ++ "gpio~p/~p", [Pin, File]).