-module(tda). -export([start/0, client/1, stop/0, co_lines/0]). -include("acse.hrl"). -include("rose.hrl"). -include("kme.hrl"). -define(TIMEOUT, 300000). -define(CONNECT_TIMEOUT, 3000). -define(HOST, "192.168.240.20"). -define(PORT, 33333). associate_request() -> {ok, UI} = acse:encode('ACSEUserInformationForCSTA', {newDefinition, #'NewACSEUserInformationForCSTA'{cSTAVersion = [versionFive]}}), acse:encode('ACSE-apdu', {aarq, #'AARQ-apdu'{ 'protocol-version' = [version1], 'application-context-name' = {1, 3, 12, 0, 218}, 'user-information' = [#'EXTERNAL'{ 'direct-reference' = {1, 3, 12, 0, 285, 200}, encoding = {'single-ASN1-type', UI}}]}}). release_request() -> acse:encode('ACSE-apdu', {rlrq, #'RLRQ-apdu'{}}). start() -> register(tda_client, spawn(?MODULE, client, [{dial, ?HOST, ?PORT}])). stop() -> tda_client ! {logout}. client({dial, Host, Port}) -> io:format("Dial ~p:~p~n", [Host, Port]), Conn = gen_tcp:connect(Host, Port, [binary, {active, once}, {packet, 2}], ?CONNECT_TIMEOUT), client(Conn); client({ok, Sock}) -> io:format("Connected~n", []), tda_client ! {login}, loop(Sock); client({error, Reason}) -> io:format("Error: ~p~n", [Reason]), {error, Reason}. loop(Sock) -> inet:setopts(Sock, [{active, once}]), io:format("Loop~n", []), receive {login} -> io:format("Login~n", []), {ok, Hello} = associate_request(), gen_tcp:send(Sock, Hello), loop(Sock); {logout} -> io:format("Logout~n", []), {ok, Bye} = release_request(), gen_tcp:send(Sock, Bye), loop(Sock); {tcp, Sock, Msg} -> io:format("Reply ~p~n", [Msg]), case decode(Sock, Msg) of ok -> loop(Sock); error -> gen_tcp:close(Sock), error end; {tcp_closed, _} -> io:format("Connection closed~n", []), closed after ?TIMEOUT -> gen_tcp:close(Sock), timeout end. decode(Sock, Msg) -> case dispatch(Msg) of rose -> {ok, Rose} = rose:decode('ROS', Msg), io:format("ROSE> ~p~n", [Rose]), rose_handler(Sock, Rose); acse -> {ok, Acse} = acse:decode('ACSE-apdu', Msg), io:format("ACSE> ~p~n", [Acse]), acse_handler(Acse) end. rose_handler(Sock, {invoke, Rose}) -> gen_tcp:send(Sock, invoke_handler(Rose)), ok. invoke_handler(#'Invoke'{invokeId = Id, opcode = Op}) -> case Op of {_, 211} -> system_status(Id, Op) end. dispatch(<>) -> case Head of 96 -> acse; 97 -> acse; 98 -> acse; 99 -> acse; 100 -> acse; 161 -> rose; 162 -> rose end. system_status(Id, Op) -> RR = #'ReturnResult_result'{opcode = Op, result = <<5,0>>}, R = #'ReturnResult'{invokeId = Id, result = RR}, case rose:encode('ROS', {returnResult, R}) of {ok, Invoke} -> Invoke; {error, Reason} -> Reason end. acse_handler({aarq, _}) -> error; acse_handler({aare, Apdu}) -> case Apdu#'AARE-apdu'.result of accepted -> ok; 'rejected-permanent' -> error; 'rejected-transient' -> error end; acse_handler({rlrq, _}) -> error; acse_handler({rlre, _}) -> error; acse_handler({abrt, _}) -> error. co_lines() -> {ok, CO} = kme:encode('KMESpecificPrivateData', {kmeSystemData, {getSystemData, {request, {deviceList, {category, {standardDevice, networkInterface}}}}}}), CO. %kme:encode('EscapeArgument', #'EscapeArgument'{privateData = CO}).