Snap7 exposes a simple and unified way to access to its objects.
Each object is created via the function xxx_Create() where xxx stands for Cli, Srv or Par.
This function returns a Handle that you must store and not modify.
Once the object is created, to use it you must call its working functions, passing them its handle.
MyServer=Srv_Create();
ReturnValue=Srv_<working function>(MyServer, <other params>);
The handle is an internal pointer (not a 24 bit descriptor), thus its size is either 32 or 64 bit, depending on the platform.
Provided wrappers define the type S7Object as native integer and handle it internally, I suggest to use them, or if you don’t plan to use wrappers, copy its definition or use an untyped pointer.
At the end, we must destroy the object via the xxx_Destroy() function, passing the handle by reference.
Srv_Destroy(&MyServer).
xxx_Destroy() first checks that the handle value is not NULL, destroys the object, then sets to zero the handle. So, erroneous multiple call to xxx_destroy will not lead to access violation.
For each
function, into the API Reference, C and Pascal prototype are
present.
For C# and object-oriented functions please refer to wrappers interface
files.
A shared library or shared object is a file that is intended to be shared by executable files and further shared objects files. Modules used by a program are loaded from individual shared objects into memory at load time or run time, rather than being copied by a linker when it creates a single monolithic executable file for the program.
A shared library has a well-defined interface by which the functions are invoked, which consists of the function name and the calling convention (stdcall, cdecl, etc..).
Beside the benefits of the shared libraries that make them a pillar of computing there are some drawbacks:
· The library approach is fully procedural. Full object-oriented languages (such as Java or C#) need a special interface code to interface them.
· Must be very careful about the parameters type and calling convention, especially if the library is meant to be used in a multi-architecture / multi-platform environment (32/64 bit – Windows/Unix).
In the libraries context, a wrapper is a piece of source code that works as glue between the user’s source code and the binary library. And it should be considered part of the library (unmodifiable).
Wrappers supplied with Snap7 are object-oriented, they not only translate the syntax but give you a more comfortable way to work.
Example:
We want to read 16 byte from DB32 of an S7300 PLC whose address is “192.168.10.100”.
We need to:
1. Create a Snap7Client.
2. Connect it to the PLC.
3. Read the DB.
4. Destroy the Client (the disconnection is automatic on destroy).
To do this, we simply include the wrapper in our source code and use the Client class as follow:
Pascal
Uses Snap7;
Var MyDB32 : packed array[0..255] of byte; // generic buffer MyClient : TS7Client;
Procedure SymplyGet; Begin MyClient:=TS7Client.Create; MyClient.ConnectTo(‘192.168.10.100’,0,2); MyClient.DBRead(32, // DB Number 0, // Start from 16, // How many @MyDB32); // Target address MyClient.Free; End; |
C#
Using Snap7;
byte[] MyDB32 = new byte[256]; static S7Client MyClient;
static void SymplyGet() {
MyClient = new S7Client(); MyClient.ConnectTo(“192.168.10.100”,0,2); MyClient.DBRead(32, 0, 16, MyDB32); MyClient = null; }
|
C++
#include “snap7.h”;
byte MyDB32[256]; // byte is a portable type of snap7.h TS7Client *Client;
void SymplyGet() {
MyClient = new TS7Client(); MyClient->ConnectTo(“192.168.10.100”,0,2); MyClient->DBRead(32, 0, 16, &MyDB32); delete MyClient; }
|
These are only a code snippets, functions return values should be checked…
If your preferred language is plain C you don't have objects, but the job is still very simply.
Here MyClient is not a class reference but it’s a handle passed to the function.
C
#include “snap7.h”;
byte MyDB32[256]; S7Object Client; // It’s a native integer
void SymplyGet() {
MyClient = Cli_Create(); Cli_ConnectTo(MyClient, “192.168.10.100”,0,2); Cli_DBRead(MyClient, 32, 0, 16, &MyDB32); Cli_Destroy(&MyClient); // passed by ref }
|
In the folder examples you will find many examples ready to run.
LabVIEW is a special case, there is a specific chapter dedicated to it since many structural considerations must be done.
However this minimalist (but working) vi reads 16 bytes from a DB.
To allow a fine tuning of the behavior of Snap7 objects, is provided an expandable method to access their internal parameters.
xxx_GetParam() and xxx_SetParam() (where xxx is Cli, Srv or Par).
The first function allows you to read a parameter and the second to write it.
The declaration is:
int xxx_GetParam(S7Object TheObject, int ParamNumber, void *pValue);
int xxx_SetParam(S7Object TheObject, int ParamNumber, void *pValue);
The first parameter, as usual, is the object handle.
ParamNumber is an integer that identifies unequivocally a parameter (see the table below).
pValue is a pointer to the variable that contains (SetParam) or will receive (GetParam) the parameter value.
ParamNumbers are already defined in the wrappers provided for all languages.
|
Value |
CLI |
SRV |
PAR |
|
p_u16_LocalPort |
1 |
|
O |
|
Socket local Port. |
p_u16_RemotePort |
2 |
O |
|
O |
Socket remote Port. |
p_i32_PingTimeout |
3 |
O |
|
O |
Client Ping timeout. |
p_i32_SendTimeout |
4 |
O |
|
O |
Socket Send timeout. |
p_i32_RecvTimeout |
5 |
O |
|
O |
Socket Recv timeout. |
p_i32_WorkInterval |
6 |
|
O |
O |
Socket worker interval. |
p_u16_SrcRef |
7 |
O |
|
O |
ISOTcp Source reference. |
p_u16_DstRef |
8 |
O |
|
O |
ISOTcp Destination reference. |
p_u16_SrcTSap |
9 |
O |
|
O |
ISOTcp Source TSAP. |
p_i32_PDURequest |
10 |
O |
|
O |
Initial PDU length request. |
p_i32_MaxClients |
11 |
|
O |
|
Max Clients allowed. |
p_i32_BSendTimeout |
12 |
|
|
O |
BSend completion sequence timeout. |
p_i32_BRecvTimeout |
13 |
|
|
O |
BRecv completion sequence timeout. |
p_u32_RecoveryTime |
14 |
|
|
O |
Disconnection recovery time. |
p_u32_KeepAliveTime |
15 |
|
|
O |
Time for (PLC) partner alive. |
For further help, the parameter name contains info about the parameter type:
u16 |
pValue points to an unsigned 16 bit integer |
i16 |
pValue points to a signed 16 bit integer |
u32 |
pValue points to an unsigned 32 bit integer |
i32 |
pValue points to a signed 32 bit integer |
u64 |
pValue points to an unsigned 64 bit integer |
i64 |
pValue points to a signed 64 bit integer |
The parameters mean will be clear reading the functions reference.
Let’s see some examples:
C++
… // Sets the MyClient Ping time to 500 ms int32_t PingTime=500; Cli_SetParam(MyClient, p_i32_PingTimeout, &PingTime);
// Sets the MyServer max number of Clients to 128 int32_t MaxClients=128; Srv_SetParam(MyServer, p_i32_MaxClients, &MaxClients);
// Gets the current MyPartner BRecv Timeout (ms) int32_t BRecvTimeout; Par_GetParam(MyPartner, p_i32_BRecvTimeout, &BRecvTimeout); //<- Here BRecvTimeout contains the value … |
Pascal
… // Sets the MyClient Ping time to 500 ms Var PingTime : integer; PingTime:=500; Cli_SetParam(MyClient, p_i32_PingTimeout, @PingTime);
// Sets the MyServer max number of Clients to 128 Var MaxClients : integer; MaxClients:=128; Srv_SetParam(MyServer, p_i32_MaxClients, @MaxClients);
// Gets the current MyPartner BRecv Timeout (ms) Var BRecvTimeout : integer; Par_GetParam(MyPartner, p_i32_BRecvTimeout, @BRecvTimeout); //<- Here BRecvTimeout contains the value … |
Remarks
C# has no generic pointers, so to avoid the use of unsafe code, overloaded methods are used into the interface class.
Not all parameters have meaning for all the three objects, p_i32_MaxClients, for example, are server specific and are not recognized by a Client or a Partner.
Default values of these parameters are already fine-tuned.
These functions are meant for an advanced/experimental use, don’t use them if “something seems to working bad” and in any case, look at the library source code to see how they operate.