-module(tda). -export([associate_request/0, associate_result/1]). -export([release_request/0, release_result/1]). -export([associate_abort/1]). -export([client/0, stop/1, loop/1, start_client/0]). -include("acse.hrl"). -include("rose.hrl"). -define(TIMEOUT, 300000). % A-ASSOCIATE Request % 60 23 AARQ-apdu % 80 02 07 80 protocol-version { version1 } % A1 07 application-context-name % 06 05 2B 0C 00 81 5A { 1 3 12 0 218 } % BE 14 user-information % 28 12 % 06 07 2B 0C 00 82 1D 81 48 direct-reference { 1 3 12 0 285 200 } % A0 07 single-ASN1-type % (ACSEUserInfomrationForCSTA) % A0 05 newDefinition % 03 03 00 08 00 cSTAVersion { versionFive } associate_request() -> {ok, UI} = acse:encode('ACSEUserInformationForCSTA', {newDefinition, #'NewACSEUserInformationForCSTA'{cSTAVersion = [versionFive]}}), Pdu = #'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}}]}, acse:encode('ACSE-apdu', {aarq, Pdu}). % Request % 60,23,80,02,07,80,a1,07,06,05,2b,0c,00,81,5a,be,14,28,12,06,07,2b,0c,00,82,1d,81,48,a0,07,a0,05,03,03,00,08,00 % <<96,35,128,2,7,128,161,7,6,5,43,12,0,129,90,190,20,40,18,6,7,43,12,0,130,29,129,72,160,7,160,5,3,3,0,8,0>> % <<96,30,161,7,6,5,43,12,0,129,90,190,19,40,17,6,7,43,12,0, 130,29,129,72,160,6,160,4,3,...>> % Accept % <<97,47,128,2,7,128,161,7,6,5,43,12,0,129,90,162,3,2,1,0,163,5,161,3,2,1,1,190,20,40,18,6,7,43,12,0,130,29,129,72,160,7,160,5,3,3,0,8,0>> % Reject % <<97,25,128,2,7,128,161,7,6,5,43,12,0,129,90,162,3,2,1,1,163,5,161,3,2,1,1>> associate_result(Bin) -> case acse:decode('AARE-apdu', Bin) of {ok, Pdu} -> Pdu#'AARE-apdu'.result; {error, Reason} -> Reason end. release_request() -> acse:encode('ACSE-apdu', {rlrq, #'RLRQ-apdu'{}}). release_result(Bin) -> acse:decode('RLRE-apdu', Bin). % <<100,3,128,1,0>> associate_abort(Bin) -> {ok, Pdu} = acse:decode('ABRT-apdu', Bin), {ok, Pdu#'ABRT-apdu'.'abort-source'}. % ROSE status % <<161,12,2,1,1,2,2,0,211,48,3,10,1,2>> % <<162,11,2,1,1,48,6,2,2,0,211,5,0>> start_client() -> register(cl, spawn(?MODULE, client, [])). client() -> Host = "192.168.240.20", case gen_tcp:connect(Host, 33333, [binary, {active, true}, {packet, 2}], 3000) of {ok, Sock} -> {ok, Hello} = associate_request(), gen_tcp:send(Sock, Hello), loop(Sock); {error, Reason} -> {error, Reason} end. stop(Sock) -> gen_tcp:close(Sock). loop(Sock) -> %inet:setopts(Sock, [{active, once}]), receive {tcp, Sock, Msg} -> decode(Sock, Msg), loop(Sock); {tcp_closed, _} -> closed after ?TIMEOUT -> stop(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(Sock, 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(Sock, {aare, Apdu}) -> ok; acse_handler(Sock, {aarq, Apdu}) -> ok; acse_handler(Sock, {rlre, _}) -> gen_tcp:close(Sock); acse_handler(Sock, {rlrq, _}) -> gen_tcp:close(Sock); acse_handler(Sock, {abrt, _}) -> gen_tcp:close(Sock).