Skip to content

Commit

Permalink
Clean-up plus addition of edoc comments on the code.
Browse files Browse the repository at this point in the history
  • Loading branch information
lehoff committed Apr 17, 2013
1 parent 51c1fb1 commit 9ea4bf2
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 48 deletions.
28 changes: 22 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,30 @@
UNAME := $(shell uname)

ifeq ($(UNAME), Darwin)
ERL_LIB=/usr/local/lib/erlang/lib/erl_interface-3.7.9
CFLAGS=-Wall -I/usr/local/include -I$(ERL_LIB)/include
XC_DIR=/usr/local/gcc-4.8.0-for-linux32
ERL_LIB=/usr/local/lib/erlang/lib/erl_interface-3.7.11
CFLAGS=-Wall -I/usr/local/include -I$(ERL_LIB)/include -I$(XC_DIR)/include
CC=$(XC_DIR)/bin/i586-pc-linux-gcc
endif

ifeq ($(UNAME), Linux)
ERL_LIB=/usr/lib/erlang/lib/erl_interface-3.7.9
CFLAGS=-Wall -I/usr/local/include -I$(ERL_LIB)/include
CC=gcc
endif

LDFLAGS=-L. -L$(ERL_LIB)/lib

PIHWMLIB = pihwm pi_gpio port_comms


LDFLAGS=-L. -L$(ERL_LIB)/lib
all: library port_comms.o gpio_port gpio_port.beam

library: $(PIHWMLIB)

$(PIHWMLIB):
@echo Building library: $@...
$(CC) $(CFLAGS) -c -lpthread -lerl_interface -lei lib/$@.c


build:
Expand All @@ -35,11 +47,15 @@ run_test:
ct_run -noshell -pa deps/*/ebin -pa ebin -sname ct -env TEST_DIR test -dir test


gpio_node: priv/gpio_node.o
gcc ${LDFLAGS} $< -lerl_interface -lei -lpthread -o $@
gpio_port: priv/gpio_port.o
$(CC) ${LDFLAGS} $< port_comms.o -lerl_interface -lei -lpthread -o $@

gpio_test: priv/gpio_test.o
$(CC) $(LDFLAGS) $< pihwm.o pi_gpio.o -lpthread -o $@


priv/%.o: c_src/%.c
gcc -g $(CFLAGS) -o $@ -c $<
$(CC) -g $(CFLAGS) -o $@ -c $<


clean_ct:
Expand Down
25 changes: 11 additions & 14 deletions examples/gpio_counter.erl
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
%%%-------------------------------------------------------------------
%%% @author Torben Hoffmann <>
%%% @copyright (C) 2013, Torben Hoffmann
%%% @doc
%%%
%%% @author Torben Hoffmann <torben@erlang-solutions.com>
%%% @copyright (C) 2013, Erlang Solutions Limited
%%% @doc Simple example that shows how to program GPIO pins in
%%% Erlang/ALE.
%%% The idea is to use two LEDs to represent 2's and 1's and just
%%% count up and down between 0 and 3 by pressing buttens for +1 and
%%% -1.
%%% @end
%%% Created : 19 Mar 2013 by Torben Hoffmann <>
%%%-------------------------------------------------------------------
-module(gpio_counter).

Expand Down Expand Up @@ -34,8 +36,6 @@
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).



%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
Expand Down Expand Up @@ -70,13 +70,6 @@ handle_info({gpio_interrupt, _Pin, _Condition},
State) ->
{noreply, State}.

set_counter_pins(N1) ->
<<Twos:1, Ones:1>> = <<N1:2>>,
gpio:pin_write(?ONES_PIN, Ones),
gpio:pin_write(?TWOS_PIN, Twos).



terminate(_Reason, _State) ->
ok.

Expand All @@ -86,6 +79,10 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
set_counter_pins(N1) ->
<<Twos:1, Ones:1>> = <<N1:2>>,
gpio:pin_write(?ONES_PIN, Ones),
gpio:pin_write(?TWOS_PIN, Twos).



77 changes: 49 additions & 28 deletions src/gpio.erl
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
%% @doc This is the real implementation of the gpio interface module.
%% It follows the API of the sim_gpio module, so there will be one
%% process per pin.
%% The main difference is that this module is talking to a c-node that
%% does the low level stuff.
%% @doc This is the implementation of the gpio interface module.
%%
%% There is one process per GPIO pin. Each process opens a C-port that
%% manipulates the hardware.
%%
%% The one-process-per-pin design has been choosen since it allows to
%% attach each pin to the appropriate place in the supervision tree of
%% the entire application.
%% @end

%% @copyright 2013 Erlang Solutions Limited

-module(gpio).

-behaviour(gen_server).

%% API
-export([start_link/2]).

%% SW API
-export([init/2,
-export([start_link/2,
release/1,
write/2,
read/1,
set_int/2]).

-export([from_port/2]).

%% %% HW manipulation
%% -export([set_value/2, %% this is for input pins
%% get_value/1 %% checking output pins
%% ]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).


-type pin() :: 0..63.
-type pin_direction() :: 'input' | 'output'.

-type pin_state() :: 0 | 1.
Expand All @@ -52,25 +49,53 @@
%%% API
%%%===================================================================

%% @doc starts a pin with the given direction.
%%
%% To simplify things we aways identify the process for a pin by the
%% pin number, so there is no need to remember the Pid of a pin
%% process spawned.
%% @todo Add init for exclusive pins
init(Pin, Direction) ->
%% @end
-spec start_link(pin(), pin_direction()) ->
{'ok', pid()} | 'ignore' | {'error', term()}.
start_link(Pin, Direction) ->
case gproc:lookup_local_name(pname(Pin)) of
undefined ->
start_link(Pin, Direction);
gen_server:start_link(?MODULE, [Pin, Direction], []);
_Pid ->
{error, pin_already_initialised}
end.



%% @doc release/1 stops the pin process and frees resources on the
%% hardware.
%% @end
-spec release(pin()) -> 'ok'.
release(Pin) ->
call_existing(Pin, release).


%% @doc write/2 sets an output pin to the value given.
%% @end
-spec write(pin(), pin_state()) -> 'ok' | {'error', 'writing_to_input_pin'}.
write(Pin, Value) ->
call_existing(Pin, {write, Value}).

%% @doc read/1 returns the value of an input pin.
%% @end
-spec read(pin()) -> pin_state() | {'error', 'reading_from_output_pin'}.
read(Pin) ->
call_existing(Pin, read).

%% @doc set_int/2 sets an interrupt on a pin with a given condition.
%% The requesting process will be sent a message with the structure
%% {gpio_interrupt, Condition} when the interrupt triggers.
%% More than one process can listen on an interrupt condition, but
%% only one interrupt condition can be set at a time.
%% @todo Specify the errors more precisely.
%% @end
-spec set_int(pin(), interrupt_condition()) -> 'ok' | {'error', Error}
when Error :: 'wrong_condition'
| term().
set_int(Pin, Condition) when Condition == rising;
Condition == falling;
Condition == both;
Expand All @@ -80,17 +105,15 @@ set_int(Pin, Condition) when Condition == rising;
set_int(_Pin, _Condition) ->
{error, wrong_condition}.

%% @doc from_port/2 should not be called from the outside!
%% It is used to transform the messages from a port into a message
%% that is sent to the pin process using call instead of forcing us to
%% handle the messages in handle_info/2.
%% @end
from_port(Pin, Msg) ->
call_existing(Pin, {from_port, Msg}).


%% %% HW input simulation
%% set_value(Pin, Value) ->
%% call_existing(Pin, {set_value, Value}).

%% %% check what an output pin has been set to.
%% get_value(Pin) ->
%% call_existing(Pin, get_value).

call_existing(Pin, Msg) ->
case gproc:lookup_local_name(pname(Pin)) of
Expand All @@ -101,8 +124,6 @@ call_existing(Pin, Msg) ->
end.


start_link(Pin, Direction) ->
gen_server:start_link(?MODULE, [Pin, Direction], []).

%%%===================================================================
%%% gen_server callbacks
Expand Down

0 comments on commit 9ea4bf2

Please sign in to comment.