diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gpio.erl | 82 | ||||
-rw-r--r-- | src/gpioerl.app.src | 11 | ||||
-rw-r--r-- | src/w1therm.erl | 43 |
3 files changed, 136 insertions, 0 deletions
diff --git a/src/gpio.erl b/src/gpio.erl new file mode 100644 index 0000000..99da9be --- /dev/null +++ b/src/gpio.erl @@ -0,0 +1,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]). diff --git a/src/gpioerl.app.src b/src/gpioerl.app.src new file mode 100644 index 0000000..16c5342 --- /dev/null +++ b/src/gpioerl.app.src @@ -0,0 +1,11 @@ +{application, gpioerl, + [ + {description, ""}, + {vsn, "1"}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {env, []} + ]}. diff --git a/src/w1therm.erl b/src/w1therm.erl new file mode 100644 index 0000000..a9810f3 --- /dev/null +++ b/src/w1therm.erl @@ -0,0 +1,43 @@ +%%% @author Guido Günther <agx@sigxcpu.org> +%%% @copyright (C) 2016, Guido Günther +%%% @doc +%%% Read and write GPIO values from userspace +%%% +%%% @reference http://www.raspberrypi-spy.co.uk/2013/03/raspberry-pi-1-wire-digital-thermometer-sensor/ +%%% @end +%%% License: LGLv3 +-module(w1therm). + +-define(W1_BASE, "/sys/bus/w1/devices/"). + +-export([get_therms/0, + read_temp/1]). + +-type therm() :: string(). + +% @doc: Get 1wire temperature famliy sensors +-spec get_therms() -> {ok, list(therm())} | {error, atom()}. +get_therms() -> + case file:list_dir(?W1_BASE) of + {error, enoent} -> {ok, []}; + {error, Error} -> {error, Error}; + {ok, Files} -> + {ok, R} = re:compile("^[0-9]{2}-.*"), + Names = [ X || X <- Files, nomatch /= re:run(X, R)], + {ok, Names} + end. + +% @doc: Read temperature from 1wire therm device in ⁰C +-spec read_temp(Therm::therm()) -> {ok, float()} | {error, atom()}. +read_temp(Therm) -> + Sysfs = therm_sysfs_path(Therm, w1_slave), + {ok, Data} = file:read_file(Sysfs), + Last = string:sub_word(binary:bin_to_list(Data), 2, $\n), + TempStr = string:sub_word(Last, 2, $=), + {Temp, []} = string:to_integer(TempStr), + {ok, Temp / 1000.0}. + +% private functions +-spec therm_sysfs_path(Therm::therm(), atom() | binary()) -> string(). +therm_sysfs_path(Therm, File) -> + io_lib:format(?W1_BASE ++ Therm ++ "/~p", [File]). |