summaryrefslogtreecommitdiff
path: root/src/tapi.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/tapi.erl')
-rw-r--r--src/tapi.erl128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/tapi.erl b/src/tapi.erl
new file mode 100644
index 0000000..4faba65
--- /dev/null
+++ b/src/tapi.erl
@@ -0,0 +1,128 @@
+-module(tapi).
+-behaviour(gen_server).
+-define(SERVER, ?MODULE).
+
+-export([start_link/0]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-export([start/0, client/1, stop/0, decode/1]).
+-export([send/1, ext/0, co/0, snapshot/1, monitor/1, button/1, dial/2]).
+
+-include("config.hrl").
+-include("opcodes.hrl").
+
+start_link() ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [?HOST, ?PORT], []).
+
+init(Args) ->
+ [Host, Port] = Args,
+ gen_tcp:connect(Host, Port, [binary, {packet, 2}], ?TIMEOUT).
+
+handle_call({ok, Reply}, _From, Socket) ->
+ gen_tcp:send(Socket, Reply),
+ {noreply, ok, Socket};
+handle_call({tcp, Socket, Data}, _From, Socket) ->
+ decode(Data),
+ {noreply, ok, Socket};
+handle_call({tcp_closed, _}, _From, Socket) ->
+ {stop, closed, Socket};
+handle_call(_Request, _From, State) ->
+ {reply, ok, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, State) ->
+ gen_tcp:close(State).
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start() ->
+ register(?MODULE, spawn(?MODULE, client, [{dial, ?HOST, ?PORT}])).
+
+stop() ->
+ counter:stop(),
+ ?MODULE ! acse:release().
+
+ext() ->
+ ?MODULE ! rose:invoke(?ESCAPE, escape:lines(station)).
+
+co() ->
+ ?MODULE ! rose:invoke(?ESCAPE, escape:lines(networkInterface)).
+
+send(Reply) ->
+ ?MODULE ! Reply.
+
+snapshot(Device) ->
+ ?MODULE ! rose:invoke(?SNAPSHOT, snapshot:encode({dialingNumber, Device})).
+
+button(Device) ->
+ ?MODULE ! rose:invoke(?BUTTON, button:encode({deviceNumber, Device})).
+
+monitor(Device) ->
+ ?MODULE ! rose:invoke(?MONITOR, monitor:encode({dialingNumber, Device})).
+
+dial(From, To) ->
+ ?MODULE ! rose:invoke(?MAKECALL, dial:encode({dialingNumber, From}, {dialingNumber, To})).
+
+client({dial, Host, Port}) ->
+ io:format("Dial ~p:~p~n", [Host, Port]),
+ Conn = gen_tcp:connect(Host, Port, [binary, {packet, 2}], ?TIMEOUT),
+ counter:start(),
+ client(Conn);
+
+client({ok, Sock}) ->
+ io:format("Connected~n", []),
+ ?MODULE ! acse:associate(),
+ loop(Sock);
+
+client({error, Reason}) ->
+ io:format("Error: ~p~n", [Reason]),
+ {error, Reason}.
+
+loop(Sock) ->
+ %inet:setopts(Sock, [{active, once}]),
+ receive
+ {ok, Reply} ->
+ io:format("Send ~p~n", [Reply]),
+ spawn(gen_tcp, send, [Sock, Reply]);
+ {tcp, Sock, Data} ->
+ io:format("Recv ~p~n", [Data]),
+ spawn(?MODULE, decode, [Data]);
+ {tcp_closed, _} ->
+ io:format("Connection closed~n", []),
+ exit(closed)
+ after ?TIMEOUT ->
+ io:format("Connection timed out~n", []),
+ exit(timeout)
+ end,
+ loop(Sock).
+
+decode(Data) ->
+ case kind(Data) of
+ rose ->
+ {ok, Rose} = rose:decode(Data),
+ io:format("ROSE> ~p~n", [Rose]),
+ rose:dispatch(Rose);
+ acse ->
+ {ok, Acse} = acse:decode(Data),
+ io:format("ACSE> ~p~n", [Acse]),
+ case acse:dispatch(Acse) of
+ error ->
+ stop();
+ _ ->
+ ok
+ end
+ end.
+
+kind(<<Head:8,_/binary>>) ->
+ proplists:get_value(Head, [{96, acse}, {97, acse}, {98, acse},
+ {99, acse}, {100, acse}, {161, rose},
+ {162, rose}, {163, rose}, {164, rose}]).