summaryrefslogtreecommitdiff
path: root/tda.erl
blob: d72739f5777fd37de404898d8df3726e1d8d2548 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
-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(<<Head:8,_/binary>>) ->
	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}).