1 /*=============================================================================|
2 |  PROJECT SNAP7                                                         1.4.0 |
3 |==============================================================================|
4 |  Copyright (C) 2013, Davide Nardella                                         |
5 |  All rights reserved.                                                        |
6 |==============================================================================|
7 |  SNAP7 is free software: you can redistribute it and/or modify               |
8 |  it under the terms of the Lesser GNU General Public License as published by |
9 |  the Free Software Foundation, either version 3 of the License, or           |
10 |  (at your option) any later version.                                         |
11 |                                                                              |
12 |  It means that you can distribute your commercial software linked with       |
13 |  SNAP7 without the requirement to distribute the source code of your         |
14 |  application and without the requirement that your application be itself     |
15 |  distributed under LGPL.                                                     |
16 |                                                                              |
17 |  SNAP7 is distributed in the hope that it will be useful,                    |
18 |  but WITHOUT ANY WARRANTY; without even the implied warranty of              |
19 |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               |
20 |  Lesser GNU General Public License for more details.                         |
21 |                                                                              |
22 |  You should have received a copy of the GNU General Public License and a     |
23 |  copy of Lesser GNU General Public License along with Snap7.                 |
24 |  If not, see  http://www.gnu.org/licenses/                                   |
25 |==============================================================================|
26 |                                                                              |
27 |  Resourceless Server example (1.4.0)                                         |
28 |  The Server ha not shared resources. On every Read/Write request a callback  |
29 |  is invoked.                                                                 |
30 |  To the callback are passed the Tag (Area, Start...) and a pointer to a data |
31 |  that you can read/write.                                                    |
32 |                                                                              |
33 |=============================================================================*/
34 
35 using System;
36 using System.Runtime.InteropServices;
37 using System.Text;
38 using Snap7;
39 
40 class ServerDemo
41 {
42     static S7Server Server;
43     private static S7Server.TSrvCallback TheEventCallBack; // <== Static var containig the callback
44     private static S7Server.TSrvRWAreaCallback TheRWAreaCallBack; // <== Static var containig the callback
45     private static byte cnt = 0;
46     //------------------------------------------------------------------------------
47     // HexDump, a very nice function, it's not mine.
48     // I found it on the net somewhere some time ago... thanks to the author ;-)
49     //------------------------------------------------------------------------------
HexDump(byte[] bytes, int Size)50     static void HexDump(byte[] bytes, int Size)
51     {
52         if (bytes == null)
53             return;
54         int bytesLength = Size;
55         int bytesPerLine = 16;
56 
57         char[] HexChars = "0123456789ABCDEF".ToCharArray();
58 
59         int firstHexColumn =
60               8                   // 8 characters for the address
61             + 3;                  // 3 spaces
62 
63         int firstCharColumn = firstHexColumn
64             + bytesPerLine * 3       // - 2 digit for the hexadecimal value and 1 space
65             + (bytesPerLine - 1) / 8 // - 1 extra space every 8 characters from the 9th
66             + 2;                  // 2 spaces
67 
68         int lineLength = firstCharColumn
69             + bytesPerLine           // - characters to show the ascii value
70             + Environment.NewLine.Length; // Carriage return and line feed (should normally be 2)
71 
72         char[] line = (new String(' ', lineLength - 2) + Environment.NewLine).ToCharArray();
73         int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine;
74         StringBuilder result = new StringBuilder(expectedLines * lineLength);
75 
76         for (int i = 0; i < bytesLength; i += bytesPerLine)
77         {
78             line[0] = HexChars[(i >> 28) & 0xF];
79             line[1] = HexChars[(i >> 24) & 0xF];
80             line[2] = HexChars[(i >> 20) & 0xF];
81             line[3] = HexChars[(i >> 16) & 0xF];
82             line[4] = HexChars[(i >> 12) & 0xF];
83             line[5] = HexChars[(i >> 8) & 0xF];
84             line[6] = HexChars[(i >> 4) & 0xF];
85             line[7] = HexChars[(i >> 0) & 0xF];
86 
87             int hexColumn = firstHexColumn;
88             int charColumn = firstCharColumn;
89 
90             for (int j = 0; j < bytesPerLine; j++)
91             {
92                 if (j > 0 && (j & 7) == 0) hexColumn++;
93                 if (i + j >= bytesLength)
94                 {
95                     line[hexColumn] = ' ';
96                     line[hexColumn + 1] = ' ';
97                     line[charColumn] = ' ';
98                 }
99                 else
100                 {
101                     byte b = bytes[i + j];
102                     line[hexColumn] = HexChars[(b >> 4) & 0xF];
103                     line[hexColumn + 1] = HexChars[b & 0xF];
104                     line[charColumn] = (b < 32 ? '·' : (char)b);
105                 }
106                 hexColumn += 3;
107                 charColumn++;
108             }
109             result.Append(line);
110             #if __MonoCS__
111                 result.Append('\n');
112             #endif
113         }
114         Console.WriteLine(result.ToString());
115     }
116 
117     //------------------------------------------------------------------------------
118     // HexDump, a very nice function, it's not mine.
119     // I found it on the net somewhere some time ago... thanks to the author ;-)
120     //------------------------------------------------------------------------------
EventCallback(IntPtr usrPtr, ref S7Server.USrvEvent Event, int Size)121     static void EventCallback(IntPtr usrPtr, ref S7Server.USrvEvent Event, int Size)
122     {
123         Console.WriteLine(Server.EventText(ref Event));
124     }
125 
SrvRWAreaCallback(IntPtr usrPtr, int Sender, int Operation, ref S7Consts.S7Tag Tag, ref S7Server.RWBuffer Buffer)126     static int SrvRWAreaCallback(IntPtr usrPtr, int Sender, int Operation, ref S7Consts.S7Tag Tag, ref S7Server.RWBuffer Buffer)
127     {
128 
129         if (Operation == S7Server.OperationRead)
130             Console.WriteLine("Read Request");
131         else
132             Console.WriteLine("Write Request");
133 
134         switch (Tag.Area)
135         {
136             case S7Server.S7AreaPE : Console.Write("Area : PE, ");
137                 break;
138             case S7Server.S7AreaPA: Console.Write("Area : PA, ");
139                 break;
140             case S7Server.S7AreaMK: Console.Write("Area : MK, ");
141                 break;
142             case S7Server.S7AreaCT: Console.Write("Area : CT, ");
143                 break;
144             case S7Server.S7AreaTM: Console.Write("Area : TM, ");
145                 break;
146             case S7Server.S7AreaDB: Console.Write("Area : DB" + System.Convert.ToString(Tag.DBNumber)+" ");
147                 break;
148             default: Console.Write("Unknown area "+System.Convert.ToString(Tag.Area));
149                 break;
150         }
151 
152         Console.Write("Start : "+ System.Convert.ToString(Tag.Start)+", ");
153         Console.WriteLine("Size : "+ System.Convert.ToString(Tag.Size));
154 
155         if (Operation == S7Server.OperationWrite)
156             HexDump(Buffer.Data, Tag.Size);
157         else
158         {
159             for (int c = 0; c < 1024; c++ )
160                 Buffer.Data[c] = cnt;
161             cnt++;
162         }
163         return 0;
164     }
165 
166 
Main(string[] args)167     static void Main(string[] args)
168     {
169         Server = new S7Server();
170 
171         // Set the callbacks (using the static var to avoid the garbage collect)
172         TheEventCallBack = new S7Server.TSrvCallback(EventCallback);
173         TheRWAreaCallBack = new S7Server.TSrvRWAreaCallback(SrvRWAreaCallback);
174 
175 
176         // Filter a bit of noise
177         Server.EventMask = 0x3ff;
178         Server.SetEventsCallBack(TheEventCallBack, IntPtr.Zero);
179         Server.SetRWAreaCallBack(TheRWAreaCallBack, IntPtr.Zero);
180 
181         // Uncomment next line if you don't want to see wrapped messages
182         // (Note : Doesn't work in Mono 2.10)
183 
184          Console.SetBufferSize(100, Int16.MaxValue - 1);
185 
186         // Start the server onto the default adapter.
187         // To select an adapter we have to use Server->StartTo("192.168.x.y").
188         // Start() is the same of StartTo("0.0.0.0");
189         int Error = Server.Start();
190         if (Error == 0)
191         {
192             // Now the server is running ... wait a key to terminate
193             Console.ReadKey();
194             Server.Stop();
195         }
196         else
197             Console.WriteLine(Server.ErrorText(Error));
198         // If you got a start error:
199         // Windows - most likely you ar running the server in a pc on wich is
200         //           installed step 7 : open a command prompt and type
201         //             "net stop s7oiehsx"    (Win32) or
202         //             "net stop s7oiehsx64"  (Win64)
203         //           And after this test :
204         //             "net start s7oiehsx"   (Win32) or
205         //             "net start s7oiehsx64" (Win64)
206         // Unix - you need root rights :-( because the isotcp port (102) is
207         //        low and so it's considered "privileged".
208 
209     }
210 }
211