1+ // /*
2+ // * Copyright 2016, 2017 MZ Automation GmbH
3+ // *
4+ // * This file is part of lib60870.NET
5+ // *
6+ // * lib60870.NET is free software: you can redistribute it and/or modify
7+ // * it under the terms of the GNU General Public License as published by
8+ // * the Free Software Foundation, either version 3 of the License, or
9+ // * (at your option) any later version.
10+ // *
11+ // * lib60870.NET is distributed in the hope that it will be useful,
12+ // * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ // * GNU General Public License for more details.
15+ // *
16+ // * You should have received a copy of the GNU General Public License
17+ // * along with lib60870.NET. If not, see <http://www.gnu.org/licenses/>.
18+ // *
19+ // * See COPYING file for the complete license text.
20+ // */
21+ //
22+ //
23+ using System ;
24+
25+ using lib60870 ;
26+ using lib60870 . CS101 ;
27+ using lib60870 . CS104 ;
28+ using System . Net ;
29+ using System . Threading ;
30+
31+ namespace cs104_redundancy_server
32+ {
33+ class MainClass
34+ {
35+ private static bool connectionRequestHandler ( object parameter , IPAddress ipAddress )
36+ {
37+ Console . WriteLine ( "New connection request from IP " + ipAddress . ToString ( ) ) ;
38+
39+ // Allow only known IP addresses!
40+ // You can implement your allowed client whitelist here
41+ if ( ipAddress . ToString ( ) . Equals ( "127.0.0.1" ) )
42+ return true ;
43+ else if ( ipAddress . ToString ( ) . Equals ( "192.168.178.70" ) )
44+ return true ;
45+ else if ( ipAddress . ToString ( ) . Equals ( "192.168.2.9" ) )
46+ return true ;
47+ else
48+ return false ;
49+ }
50+
51+ private static void connectionEventHandler ( object parameter , ClientConnection connection , ClientConnectionEvent conEvent )
52+ {
53+ Console . WriteLine ( "Connection {0}:{1} - {2}" , connection . RemoteEndpoint . Address . ToString ( ) ,
54+ connection . RemoteEndpoint . Port , conEvent . ToString ( ) ) ;
55+ }
56+
57+ private static bool interrogationHandler ( object parameter , IMasterConnection connection , ASDU asdu , byte qoi )
58+ {
59+ Console . WriteLine ( "Interrogation for group " + qoi ) ;
60+
61+ ApplicationLayerParameters cp = connection . GetApplicationLayerParameters ( ) ;
62+
63+ connection . SendACT_CON ( asdu , false ) ;
64+
65+ // send information objects
66+ ASDU newAsdu = new ASDU ( cp , CauseOfTransmission . INTERROGATED_BY_STATION , false , false , 2 , 1 , false ) ;
67+
68+ newAsdu . AddInformationObject ( new MeasuredValueScaled ( 100 , - 1 , new QualityDescriptor ( ) ) ) ;
69+
70+ newAsdu . AddInformationObject ( new MeasuredValueScaled ( 101 , 23 , new QualityDescriptor ( ) ) ) ;
71+
72+ newAsdu . AddInformationObject ( new MeasuredValueScaled ( 102 , 2300 , new QualityDescriptor ( ) ) ) ;
73+
74+ connection . SendASDU ( newAsdu ) ;
75+
76+ newAsdu = new ASDU ( cp , CauseOfTransmission . INTERROGATED_BY_STATION , false , false , 3 , 1 , false ) ;
77+
78+ newAsdu . AddInformationObject ( new MeasuredValueScaledWithCP56Time2a ( 103 , 3456 , new QualityDescriptor ( ) , new CP56Time2a ( DateTime . Now ) ) ) ;
79+
80+ connection . SendASDU ( newAsdu ) ;
81+
82+ newAsdu = new ASDU ( cp , CauseOfTransmission . INTERROGATED_BY_STATION , false , false , 2 , 1 , false ) ;
83+
84+ newAsdu . AddInformationObject ( new SinglePointWithCP56Time2a ( 104 , true , new QualityDescriptor ( ) , new CP56Time2a ( DateTime . Now ) ) ) ;
85+
86+ connection . SendASDU ( newAsdu ) ;
87+
88+ // send sequence of information objects
89+ newAsdu = new ASDU ( cp , CauseOfTransmission . INTERROGATED_BY_STATION , false , false , 2 , 1 , true ) ;
90+
91+ newAsdu . AddInformationObject ( new SinglePointInformation ( 200 , true , new QualityDescriptor ( ) ) ) ;
92+ newAsdu . AddInformationObject ( new SinglePointInformation ( 201 , false , new QualityDescriptor ( ) ) ) ;
93+ newAsdu . AddInformationObject ( new SinglePointInformation ( 202 , true , new QualityDescriptor ( ) ) ) ;
94+ newAsdu . AddInformationObject ( new SinglePointInformation ( 203 , false , new QualityDescriptor ( ) ) ) ;
95+ newAsdu . AddInformationObject ( new SinglePointInformation ( 204 , true , new QualityDescriptor ( ) ) ) ;
96+ newAsdu . AddInformationObject ( new SinglePointInformation ( 205 , false , new QualityDescriptor ( ) ) ) ;
97+ newAsdu . AddInformationObject ( new SinglePointInformation ( 206 , true , new QualityDescriptor ( ) ) ) ;
98+ newAsdu . AddInformationObject ( new SinglePointInformation ( 207 , false , new QualityDescriptor ( ) ) ) ;
99+
100+ connection . SendASDU ( newAsdu ) ;
101+
102+ newAsdu = new ASDU ( cp , CauseOfTransmission . INTERROGATED_BY_STATION , false , false , 2 , 1 , true ) ;
103+
104+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 300 , - 1.0f ) ) ;
105+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 301 , - 0.5f ) ) ;
106+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 302 , - 0.1f ) ) ;
107+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 303 , .0f ) ) ;
108+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 304 , 0.1f ) ) ;
109+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 305 , 0.2f ) ) ;
110+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 306 , 0.5f ) ) ;
111+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 307 , 0.7f ) ) ;
112+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 308 , 0.99f ) ) ;
113+ newAsdu . AddInformationObject ( new MeasuredValueNormalizedWithoutQuality ( 309 , 1f ) ) ;
114+
115+ connection . SendASDU ( newAsdu ) ;
116+
117+ connection . SendACT_TERM ( asdu ) ;
118+
119+ return true ;
120+ }
121+
122+ private static bool asduHandler ( object parameter , IMasterConnection connection , ASDU asdu )
123+ {
124+
125+ if ( asdu . TypeId == TypeID . C_SC_NA_1 ) {
126+ Console . WriteLine ( "Single command" ) ;
127+
128+ SingleCommand sc = ( SingleCommand ) asdu . GetElement ( 0 ) ;
129+
130+ Console . WriteLine ( sc . ToString ( ) ) ;
131+ }
132+ else if ( asdu . TypeId == TypeID . C_CS_NA_1 ) {
133+
134+
135+ ClockSynchronizationCommand qsc = ( ClockSynchronizationCommand ) asdu . GetElement ( 0 ) ;
136+
137+ Console . WriteLine ( "Received clock sync command with time " + qsc . NewTime . ToString ( ) ) ;
138+ }
139+
140+ return true ;
141+ }
142+
143+ public static void Main ( string [ ] args )
144+ {
145+ bool running = true ;
146+
147+ Console . CancelKeyPress += delegate ( object sender , ConsoleCancelEventArgs e ) {
148+ e . Cancel = true ;
149+ running = false ;
150+ } ;
151+
152+ Server server = new Server ( ) ;
153+ //server.DebugOutput = true;
154+
155+ /* Configure a server with three redundancy groups */
156+
157+ server . ServerMode = ServerMode . MULTIPLE_REDUNDANCY_GROUPS ;
158+ server . MaxQueueSize = 10 ;
159+ server . MaxOpenConnections = 6 ;
160+
161+ RedundancyGroup redGroup1 = new RedundancyGroup ( "red-group-1" ) ;
162+ redGroup1 . AddAllowedClient ( "192.168.2.9" ) ;
163+
164+ RedundancyGroup redGroup2 = new RedundancyGroup ( "red-group-2" ) ;
165+ redGroup2 . AddAllowedClient ( "192.168.2.223" ) ;
166+ redGroup2 . AddAllowedClient ( "192.168.2.222" ) ;
167+
168+ /* add a "catch all" redundancy groups - all other connections are handled by this group */
169+ RedundancyGroup redGroup3 = new RedundancyGroup ( "catch all" ) ;
170+
171+ server . AddRedundancyGroup ( redGroup1 ) ;
172+ server . AddRedundancyGroup ( redGroup2 ) ;
173+ server . AddRedundancyGroup ( redGroup3 ) ;
174+
175+ server . SetConnectionRequestHandler ( connectionRequestHandler , null ) ;
176+
177+ server . SetConnectionEventHandler ( connectionEventHandler , null ) ;
178+
179+ server . SetInterrogationHandler ( interrogationHandler , null ) ;
180+
181+ server . SetASDUHandler ( asduHandler , null ) ;
182+
183+ server . Start ( ) ;
184+
185+ int waitTime = 1000 ;
186+
187+ while ( running )
188+ {
189+ Thread . Sleep ( 100 ) ;
190+
191+ if ( waitTime > 0 )
192+ waitTime -= 100 ;
193+ else {
194+
195+ ASDU newAsdu = new ASDU ( server . GetApplicationLayerParameters ( ) , CauseOfTransmission . PERIODIC , false , false , 2 , 1 , false ) ;
196+
197+ newAsdu . AddInformationObject ( new MeasuredValueScaled ( 110 , - 1 , new QualityDescriptor ( ) ) ) ;
198+
199+ server . EnqueueASDU ( newAsdu ) ;
200+
201+ waitTime = 1000 ;
202+ }
203+ }
204+
205+ Console . WriteLine ( "Stop server" ) ;
206+ server . Stop ( ) ;
207+ }
208+ }
209+ }
0 commit comments