Current section
Files
Jump to
Current section
Files
src/pmod_maxsonar.erl
-module(pmod_maxsonar).
-include("grisp_docs.hrl").
?moduledoc("""
[Pmod MAXSONAR](https://store.digilentinc.com/pmodmaxsonar-maxbotix-ultrasonic-range-finder/)
module.
The Pmod MAXSONAR cyclically sends measurements via the UART interface.
This module converts and stores the latest measurement.
Start the driver with
```
1> grisp:add_device(uart, pmod_maxsonar).
```
""").
-behaviour(gen_server).
-include("grisp_port.hrl").
% API
-export([start_link/2]).
-export([get/0]).
% Callbacks
-export([init/1]).
-export([handle_call/3]).
-export([handle_cast/2]).
-export([handle_info/2]).
-export([code_change/3]).
-export([terminate/2]).
%--- Records -------------------------------------------------------------------
-record(state, {port, last_val}).
%--- API -----------------------------------------------------------------------
?doc(false).
start_link(Slot, _Opts) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, Slot, []).
?doc("""
Get the latest measured distance in inches.
""").
-spec get() -> integer().
get() ->
gen_server:call(?MODULE, get_value).
%--- Callbacks -----------------------------------------------------------------
?doc(false).
init(Slot = uart) ->
Port = ?PORT_OPEN({spawn_driver, "grisp_termios_drv"}, [binary]),
grisp_devices:register(Slot, ?MODULE),
{ok, #state{port = Port}}.
?doc(false).
handle_call(get_value, _From, #state{last_val = Val} = State) ->
{reply, Val, State}.
?doc(false).
handle_cast(Request, _State) -> error({unknown_cast, Request}).
?doc(false).
handle_info({Port, {data, Data}}, #state{port = Port} = State) ->
case Data of
% Format of response is 'Rxxx\n' where xxx is the decimal
% representation of the measured range in inches (2.54cm)
% (left-padded with zeros - so there are always three digits)
<<$R, D1, D2, D3, $\n>> when $0 =< D1, D1 =< $9,
$0 =< D2, D2 =< $9,
$0 =< D3, D3 =< $9 ->
% Val is given in inches
Val = (D1 - $0) * 100 + (D2 - $0) * 10 + (D3 - $0),
{noreply, State#state{last_val = Val}};
% Sometimes for no obvious reason we receive
% a different value from the sonar.
% Instead of $R we get two garbage characters
<<_, _, D1, D2, D3, $\n>> when $0 =< D1, D1 =< $9,
$0 =< D2, D2 =< $9,
$0 =< D3, D3 =< $9 ->
% Val is given in inches
Val = (D1 - $0) * 100 + (D2 - $0) * 10 + (D3 - $0),
{noreply, State#state{last_val = Val}};
_ ->
{noreply, State}
end.
?doc(false).
code_change(_OldVsn, State, _Extra) -> {ok, State}.
?doc(false).
terminate(_Reason, _State) -> ok.