
-module(drv).
-compile(export_all).

% test api

-define(SERVER, ?MODULE).

start(Path) ->
    gen_server:start({local, ?SERVER}, ?MODULE, Path, []).

test_call(Msg) ->
    gen_server:call(?SERVER, {test, self(), Msg}).

% gen_server callbacks

-record(state, {port}).

init(Path) ->
    process_flag(trap_exit, true),
    OpenPort = fun() ->
        case catch open_port({spawn, drv}, [binary]) of
        Port when is_port(Port) ->
            {ok, #state{port = Port}};
        Error ->
            {stop, Error}
        end
    end,
    case erl_ddll:load_driver(Path, "drv") of
    ok ->
        OpenPort();
    {error, already_loaded} ->
        OpenPort();
    Other ->
        {stop, Other}
    end.

handle_call(Msg, From, State = #state{port = Port}) when is_port(Port) ->
    port_command(Port, term_to_binary({From, Msg})),
    {noreply, State};

handle_call(_Msg, _From, State) ->
    {reply, ok, State}.

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({Port, {data, Bin}}, State) when is_port(Port), is_binary(Bin) ->
    case binary_to_term(Bin) of
    {data, To, Msg} ->
        gen_server:reply(To, {data, Msg});
    Other ->
        io:format("test> unknown reply: ~p~n", [Other])
    end,
    {noreply, State};

handle_info(Msg, State) ->
    io:format("test> other message: ~p~n", [Msg]),
    {noreply, State}.

terminate(_Reason, #state{port = Port}) when is_port(Port) ->
    port_close(Port),
    ok;

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

% end of gen_server callbacks

t() ->
    start("."),
    Ret1 = (catch test_call("lalala")),
    io:format("~nret1: '~p'~n", [Ret1]),
    Ret2 = (catch test_call("pipipi")),
    io:format("~nret2: '~p'~n", [Ret2]).
