APP S7 is a pure C# implementation of the S7 Protocol. APP S7 is deployed as a single source file that contains some classes that you can use directly in your .NET project to communicate with S7 PLCs. It’s designed to work with small hardware .NET-based or even for large projects which don’t need extended control functions.
Main features
- Fully standard “safe managed” C# code without any dependencies.
- Virtually every hardware with an Ethernet adapter able to run a .NET Core can be connected to an S7 PLC.
- Packed protocol headers to improve performances.
- Helper class to access to all S7 types without worrying about Little-Big endian conversion.
- Compatible with Universal Windows Platform including Win10 IoT
Licensing
The APP_S7 Driver requires a license for long term operation. This can be requested by contacting:
contact@appliedprojectsengineering.com
S7Client reference
Administrative functions
These methods allow controlling the behavior a Client Object.
Function
|
Purpose
|
ConnectTo
|
Connects a Client Object to a PLC.
|
SetConnectionType
|
Sets the connection type (PG/OP/S7Basic)
|
SetConnectionParams
|
Sets Address, Local and Remote TSAP for the connection.
|
Connect
|
Connects a Client Object to a PLC with implicit parameters.
|
Disconnect
|
Disconnects a Client.
|
SetConnectionType
Description
Sets the connection resource type, i.e. the way in which the Clients connects to a PLC.
Declaration
public void SetConnectionType(short ConnectionType)
Parameters
|
Type
|
Dir.
|
|
ConnectionType
|
short
|
In
|
See the table
|
Connection type table
Connection Type
|
Value
|
Helper Const
|
PG
|
0x01
|
S7.PG
|
OP
|
0x02
|
S7.OP
|
S7 Basic
|
0x03..0x10
|
S7.S7_BASIC
|
ConnectTo
Description
Connects the client to the hardware at (IP, Rack, Slot) Coordinates.
Declaration
public int ConnectTo(String Address, int Rack, int Slot)
Parameters
|
Type
|
Dir.
|
|
Address
|
String
|
In
|
PLC/Equipment IPV4 Address ex. “192.168.1.12”
|
Rack
|
int
|
In
|
PLC Rack number (see below)
|
Slot
|
int
|
In
|
PLC Slot number (see below)
|
Return value
- 0 : The Client is successfully connected (or was already connected).
- Other values : see the Errors Code List.
Rack and Slot
In addition to the IP Address, that we all understand, there are two other parameters that index the unit : Rack (0..7) and Slot (1..31) that you find into the hardware configuration of your project, for a physical component, or into the Station Configuration manager for WinAC.
There is however some special cases for which those values are fixed or can work with a default as you can see in the next table.
|
Rack
|
Slot
|
|
S7 300 CPU
|
0
|
2
|
Always
|
S7 400 CPU
|
Not fixed
|
Follow the hardware configuration.
|
WinAC CPU
|
Not fixed
|
Follow the hardware configuration.
|
S7 1200 CPU
|
0
|
0
|
Or 0, 1
|
S7 1500 CPU
|
0
|
0
|
Or 0, 1
|
WinAC IE
|
0
|
0
|
Or follow Hardware configuration.
|
Let’s see some examples of hardware configuration:
S7 400 Rack
|
Rack
|
Slot
|
CPU 1
|
0
|
4
|
CPU 2
|
0
|
11
|
The same concept for WinAC CPU which index can vary inside the PC Station Rack.
S7300 Rack
S7300 CPU is always present in Rack 0 at Slot 2
SetConnectionParams
Description
Sets internally (IP, LocalTSAP, RemoteTSAP) Coordinates.
Declaration
public void SetConnectionParams(String Address, int LocalTSAP,
int RemoteTSAP)
Parameters
|
Type
|
Dir.
|
|
Address
|
String
|
In
|
PLC/Equipment IPV4 Address ex. “192.168.1.12”
|
LocalTSAP
|
int
|
In
|
Local TSAP (PC TSAP)
|
RemoteTSAP
|
int
|
In
|
Remote TSAP (PLC TSAP)
|
Remarks
This function must be called just before Connect().
Connect
Description
Connects the client to the PLC with the parameters specified in the previous call of ConnectTo() or SetConnectionParams().
Declaration
public int Connect()
Return value
- 0 : The Client is successfully connected (or was already connected).
- Other values : see the Errors Code List.
Remarks
This function can be called only after a previous of ConnectTo() or SetConnectionParams() which internally sets Address and TSAPs.
Disconnect
Description
Disconnects “gracefully” the Client from the PLC.
Declaration
public void Disconnect()
Remarks
This function can be called safely multiple times.
After calling this function LastError = 0 and Connected = false.
Base Data I/O functions
These functions allow the Client to exchange data with a PLC.
Function
|
Purpose
|
ReadArea
|
Reads a data area from a PLC.
|
WriteArea
|
Writes a data area into a PLC.
|
ReadMultiVars
|
Reads different kind of variables from a PLC simultaneously.
|
WriteMultiVars
|
Writes different kind of variables into a PLC simultaneously.
|
ReadArea
Description
This is the main function to read data from a PLC.
With it you can read DB, Inputs, Outputs, Merkers, Timers and Counters.
Declaration
public int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)
public int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer, ref int BytesRead)
Parameters
|
Type
|
Dir.
|
Mean
|
Area
|
int
|
In
|
Area identifier.
|
DBNumber
|
int
|
In
|
DB Number if Area = S7AreaDB, otherwise is ignored.
|
Start
|
int
|
In
|
Offset to start
|
Amount
|
int
|
In
|
Amount of elements to read (1)
|
Wordlen
|
int
|
In
|
Word size (2)
|
Buffer
|
Byte Buffer
|
In
|
Buffer
|
BytesRead
|
int
|
Out
|
Number of bytes read (3)
|
(1) Note the use of the parameter name “amount”, it means quantity of elements, not byte size.
Area table
|
Value
|
Mean
|
S7Consts.S7AreaPE
|
0x81
|
Process Inputs.
|
S7Consts.S7AreaPA
|
0x82
|
Process Outputs.
|
S7Consts.S7AreaMK
|
0x83
|
Merkers.
|
S7Consts.S7AreaDB
|
0x84
|
DB
|
S7Consts.S7AreaCT
|
0x1C
|
Counters.
|
S7Consts.S7AreaTM
|
0x1D
|
Timers
|
WordLen table
|
Value
|
Mean
|
S7WLBit
|
0x01
|
Bit (inside a word)
|
S7WLByte
|
0x02
|
Byte (8 bit)
|
S7WLWord
|
0x04
|
Word (16 bit)
|
S7WLDWord
|
0x06
|
Double Word (32 bit)
|
S7WLReal
|
0x08
|
Real (32 bit float)
|
S7WLCounter
|
0x1C
|
Counter (16 bit)
|
S7WLTimer
|
0x1D
|
Timer (16 bit)
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
Remarks
As said, every data packet exchanged with a PLC must fit in a PDU, whose size is fixed and varies from 240 up to 960 bytes.
This function completely hides this concept, the data that you can transfer in a single call depends only on the size available of the data area (i.e. obviously, you cannot read 1024 bytes from a DB whose size is 300 bytes).
If this data size exceeds the PDU size, the packet is automatically split across more subsequent transfers.
If either S7AreaCT or S7AreaTM is selected, WordLen must be either S7WLCounter or S7WLTimer (However no error is raised and the values are internally fixed).
Your buffer should be large enough to receive the data.
Particularly:
Buffer size (byte) = Word size * Amount
Where:
|
Word size
|
S7Consts.S7WLBit
|
1
|
S7Consts.S7WLByte
|
1
|
S7Consts.S7WLWord
|
2
|
S7Consts.S7WLDWord
|
4
|
S7Consts.S7WLReal
|
4
|
S7Consts.S7WLCounter
|
2
|
S7Consts.S7WLTimer
|
2
|
Notes
(2) When WordLen=S7WLBit the Offset (Start) must be expressed in bits.
Ex. The Start for DB4.DBX 10.3 is (10*8)+3 = 83.
(3) Since Amount is the number of elements read, BytesRead returns the effective number of bytes.
WriteArea
Description
This is the main function to write data into a PLC. It’s the complementary function of ReadArea(), the parameters and their meanings are the same.
The only difference is that the data is transferred from the byte buffer into PLC.
Declaration
public int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)
public int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer, ref int BytesWritten)
See ReadArea() for parameters and remarks.
Use S7 helper methods to insert S7 data types (int, word, real …) into the byte buffer.
ReadMultiVars
Description
This is function allows to read different kind of variables from a PLC in a single call.
With it you can read DB, Inputs, Outputs, Merkers, Timers and Counters.
Declaration
public int ReadMultiVars(S7DataItem[] Items, int ItemsCount)
Parameters
|
Type
|
Dir.
|
|
Item
|
S7DataItem[]
|
In
|
See below
|
ItemsCount
|
integer
|
In
|
Number of Items to read.
|
S7DataItem struct
|
Type
|
Dir.
|
|
Area
|
int
|
In
|
Area identifier.
|
Wordlen
|
int
|
In
|
Word size
|
Result
|
int
|
Out
|
Item operation result (2)
|
DBNumber
|
int
|
In
|
DB Number if Area = S7AreaDB, otherwise is ignored.
|
Start
|
int
|
In
|
Offset to start
|
Amount
|
int
|
In
|
Amount of words to read (1)
|
pData
|
IntPtr
|
In
|
Pointer to user Buffer
|
(1) Note the use of the parameter name “amount”, it means quantity of words, not byte size.
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
(2) Since could happen that some variables are read, some other not because maybe they don't exist in PLC. Is important to check the single item Result.
Remarks
To use ReadMultiVars a special class is supplied S7MultiVar that avoids the use of unsafe code (since there is a IntPtr)
Due the different kind of variables involved , there is no split feature available for this function, so the maximum data size must not exceed the PDU size.
The advantage of this function becomes big when you have many small noncontiguous variables to be read.
WriteMultiVars
Description
This is function allows to write different kind of variables from a PLC in a single call.
With it you can read DB, Inputs, Outputs, Merkers, Timers and Counters.
Declaration
public int WriteMultiVars(S7DataItem[] Items, int ItemsCount)
Parameters
|
Type
|
Dir.
|
|
Item
|
S7DataItem[]
|
In
|
See below
|
ItemsCount
|
integer
|
In
|
Number of Items to write.
|
S7DataItem struct
|
Type
|
Dir.
|
|
Area
|
int
|
In
|
Area identifier.
|
Wordlen
|
int
|
In
|
Word size
|
Result
|
int
|
Out
|
Item operation result (2)
|
DBNumber
|
int
|
In
|
DB Number if Area = S7AreaDB, otherwise is ignored.
|
Start
|
int
|
In
|
Offset to start
|
Amount
|
int
|
In
|
Amount of words to write (1)
|
pData
|
IntPtr
|
In
|
Pointer to user Buffer
|
(2) Note the use of the parameter name “amount”, it means quantity of words, not byte size.
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
(2) Since could happen that some variables are written, some other not because maybe they don't exist in PLC. Is important to check the single item Result.
Remarks
To use WriteMultiVars a special class is supplied S7MultiVar that avoids the use of unsafe code (since there is a IntPtr)
Due the different kind of variables involved , there is no split feature available for this function, so the maximum data size must not exceed the PDU size
The advantage of this function becomes big when you have many small noncontiguous variables to be written.
Lean Data I/O functions
These are utility functions that simplify the use of ReadArea and WriteArea.
I.e. they call internally ReadArea and WriteArea passing the correct Area and WordLen.
Function
|
Purpose
|
DBRead
|
Reads a part of a DB from a PLC.
|
DBWrite
|
Writes a part of a DB into a PLC.
|
ABRead
|
Reads a part of IPU area from a PLC.
|
ABWrite
|
Writes a part of IPU area into a PLC.
|
EBRead
|
Reads a part of IPI area from a PLC.
|
EBWrite
|
Writes a part of IPI area into a PLC.
|
MBRead
|
Reads a part of Merkers area from a PLC.
|
MBWrite
|
Writes a part of Merkers area into a PLC.
|
TMRead
|
Reads timers from a PLC.
|
TMWrite
|
Write timers into a PLC.
|
CTRead
|
Reads counters from a PLC.
|
CTWrite
|
Write counters into a PLC.
|
Block oriented functions
Function
|
Purpose
|
GetAgBlockInfo
|
Returns info about a given block in PLC memory.
|
DBGet
|
Uploads a DB from the PLC
|
DBFill
|
Fills a DB into the PLC with a given value.
|
GetAgBlockInfo
Description
Returns some information about a given block.
This function is very useful if you need to read or write data in a DB which you do not know the size in advance (see MC7Size field).
This function is used internally by DBGet.
Declaration
public int GetAgBlockInfo(int BlockType, int BlockNumber,
ref S7BlockInfo Block)
Parameters
|
Type
|
Dir.
|
|
BlockType
|
int
|
In
|
Type of Block that we need
|
BlockNum
|
int
|
In
|
Number of Block
|
Block
|
S7BlockInfo
|
in
|
S7BlockInfo struct
|
BlockType values
Helper Const
|
Type
|
Value
|
S7Consts.Block_OB
|
OB
|
0x38
|
S7 Consts.Block_DB
|
DB
|
0x41
|
S7 Consts.Block_SDB
|
SDB
|
0x42
|
S7 Consts.Block_FC
|
FC
|
0x43
|
S7 Consts.Block_SFC
|
SFC
|
0x44
|
S7 Consts.Block_FB
|
FB
|
0x45
|
S7 Consts.Block_SFB
|
SFB
|
0x46
|
S7BlockInfo struct
public struct S7BlockInfo {
public int BlkType; // Block Type (see SubBlkType table)
public int BlkNumber; // Block number
public int BlkLang; // Block Language (see LangType Table)
public int BlkFlags; // Block flags (bitmapped)
public int MC7Size; // The real size in bytes
public int LoadSize; // Load memory size
public int LocalData; // Local data
public int SBBLength; // SBB Length
public int CheckSum; // Checksum
public int Version; // Version (BCD 00<HI><LO>)
public string; // Code date
public string; // Interface date
public string; // Author
public string; // Family
public string; // Header
};
|
This struct is filled by the function, some fields require additional info:
SubBlockType table
|
Value
|
Type
|
SubBlk_OB
|
0x08
|
OB
|
SubBlk_DB
|
0x0A
|
DB
|
SubBlk_SDB
|
0x0B
|
SDB
|
SubBlk_FC
|
0x0C
|
FC
|
SubBlk_SFC
|
0x0D
|
SFC
|
SubBlk_FB
|
0x0E
|
FB
|
SubBlk_SFB
|
0x0F
|
SFB
|
LangType table
|
Value
|
Block Language
|
BlockLangAWL
|
0x01
|
AWL
|
BlockLangKOP
|
0x02
|
KOP
|
BlockLangFUP
|
0x03
|
FUP
|
BlockLangSCL
|
0x04
|
SCL
|
BlockLangDB
|
0x05
|
DB
|
BlockLangGRAPH
|
0x06
|
GRAPH
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
DBGet
Description
Read an entire DB from the PLC without the need of specifying its size. As output SizeRead will contain the size read.
This function is not subject to the security level set.
Declaration
public int DBGet(int DBNumber, byte[] usrData, ref int Size)
Parameters
|
Type
|
Dir.
|
|
DBNumber
|
int
|
In
|
DB Number
|
Data
|
byte array
|
in
|
Address of the user buffer
|
SizeRead
|
int ref
|
In/Out
|
In : Buffer size supplied
Out : Number of bytes read
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
Remarks
This function first gathers the DB size via GetAgBlockInfo then calls ReadArea if the Buffer size is greater than the DB size, otherwise returns an error.
DBFill
Description
Fills a DB in AG with a given byte without the need of specifying its size.
Declaration
public int Cli_DBFill(int DBNumber, int FillChar);
Parameters
|
Type
|
Dir.
|
|
DBNumber
|
integer 32
|
In
|
DB Number
|
FillChar
|
Integer 32
|
in
|
Byte pattern
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
Remarks
Fillchar is an integer for efficiency reasons, only the lowest byte is used.
Date/Time functions
These functions allow to read/modify the date and time of a PLC.
Imagine a production line in which each PLC saves the data with date/time field inside, it is very important that the date be up to date.
Both CP X43 and internal PN allow to synchronize date and time but you need an NTP server, and in some cases (old hardware or CP343-1 Lean or old firmware release) this doesn’t work properly.
Snap7 Client, using the same method of S7 Manager, always works.
Function
|
Purpose
|
GetPlcDateTime
|
Returns the PLC date/time.
|
SetPlcDateTime
|
Sets the PLC date/time with a given value.
|
SetPlcSystemDateTime
|
Sets the PLC date/time with the host (PC) date/time.
|
GetPlcDateTime
Description
Reads PLC date and time into a C# DateTime class instance.
Declaration
public int GetPlcDateTime(ref DateTime DT)
Parameters
|
Type
|
Dir.
|
|
DateTime
|
Date
|
In
|
DateTime class instance
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
SetPlcDateTime
Description
Sets the PLC date and time.
Declaration
public int SetPlcDateTime(DateTime DT)
Parameters
|
Type
|
Dir.
|
|
DateTime
|
Date
|
In
|
DateTime class instance
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
SetPlcSystemDateTime
Description
Sets the PLC date and time in accord to the PC system Date/Time.
Declaration
public int SetPlcSystemDateTime()
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
System info functions
these functions access to SZL (or SSL - System Status List) to give you all the same information that you can get from S7 Manager.
System Status List
The system status list (SSL) describes the current status of a programmable logic controller.
The contents of the SSL can only be read using information functions but cannot be modified. The partial lists are virtual lists, in other words, they are only created by the operating system of the CPUs when specifically requested.
You can access to system status list using SFC 51 too "RDSYSST."
To read a partial list you must specify its ID and Index.
For a detailed description of SZL see:
- 33 of "System Software for S7-300/400 System and Standard Functions".
Function
|
Purpose
|
ReadSZL
|
Reads a partial list of given ID and Index.
|
GetOrderCode
|
Returns the CPU order code.
|
GetCpuInfo
|
Returns some information about the AG.
|
GetCpInfo
|
Returns some information about the CP (communication processor).
|
ReadSZL
Description
Reads a partial list of given ID and INDEX.
Declaration
public int ReadSZL(int ID, int Index, ref S7SZL SZL, ref int Size)
Parameters
|
Type
|
Dir.
|
|
ID
|
int
|
In
|
List ID
|
Index
|
int
|
In
|
List Index
|
SZL
|
S7Szl
|
in
|
S7Szl class instance
|
Size
|
int
|
out
|
Size Read in bytes
|
S7SZL
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SZL_HEADER
{
public UInt16 LENTHDR;
public UInt16 N_DR;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct S7SZL
{
public SZL_HEADER Header;
[MarshalAs(UnmanagedType.ByValArray)]
public byte[] Data;
};
|
|
Type
|
Dir.
|
Mean
|
LENTHDR
|
integer
|
Out
|
Length of a data record of the partial list in bytes
|
N_DR
|
integer
|
Out
|
Number of data records contained in the partial list.
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
Remarks
Remember to allocate the Data[] buffer (see the demo)
GetOrderCode
Description
Gets CPU order code and version info.
Declaration
public int GetOrderCode(S7OrderCode Info)
Parameters
|
Type
|
Dir.
|
|
Info
|
S7OrderCode
|
Out
|
See below
|
public struct S7OrderCode
{
public string Code;
public byte V1; // Version 1st digit
public byte V2; // Version 2nd digit
public byte V3; // Version 3th digit
};
|
The Order code is a string such as “6ES7 151-8AB01-0AB0”
GetCpuInfo
Description
Gets CPU module name, serial number and other info.
Declaration
public int GetCpuInfo(S7CpuInfo Info)
Parameters
|
Type
|
Dir.
|
|
Info
|
S7CpuInfo
|
Out
|
See below
|
public struct S7CpuInfo
{
public string ModuleTypeName;
public string SerialNumber;
public string ASName;
public string Copyright;
public string ModuleName;
}
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
GetCpInfo
Description
Gets CP (communication processor) info.
Declaration
public int GetCpInfo(S7CpInfo Info)
Parameters
|
Type
|
Dir.
|
|
Info
|
S7CpInfo
|
Out
|
See below
|
S7CpInfo
public struct S7CpInfo
{
public int MaxPduLength;
public int MaxConnections;
public int MaxMpiRate;
public int MaxBusRate;
};
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
PLC control functions
With these control function it’s possible to Start/Stop a CPU and read the PLC status.
Function
|
Purpose
|
PlcColdStart
|
Puts the CPU in RUN mode performing an COLD START.
|
PlcHotStart
|
Puts the CPU in RUN mode performing an HOT START.
|
PlcStop
|
Puts the CPU in STOP mode.
|
PlcGetStatus
|
Returns the CPU status (running/stopped).
|
PlcColdStart
Description
Puts the CPU in RUN mode performing an COLD START.
Declaration
public int PlcColdStart()
Return value
- 0 : The function was accomplished with no errors.
- Other values : Either the PLC is already running or the current protection level is not met to perform this operation.
Remarks
This function is subject to the security level set.
PlcHotStart
Description
Puts the CPU in RUN mode performing an HOT START.
Declaration
public int PlcHotStart()
Return value
- 0 : The function was accomplished with no errors.
- Other values : Either the PLC is already running or the current protection level is not met to perform this operation.
Remarks
This function is subject to the security level set.
PlcStop
Description
Puts the CPU in STOP mode.
Declaration
public int PlcStop()
Return value
- 0 : The function was accomplished with no errors.
- Other values : Either the PLC is already stopped or the current protection level is not met to perform this operation.
Remarks
This function is subject to the security level set.
PlcGetStatus
Description
Returns the CPU status (running/stopped) into Status.Value.
Declaration
public int GetPlcStatus(ref int Status)
Parameters
|
Type
|
Dir.
|
|
Status
|
int
|
Out
|
Plc status
|
Status values
Helper Const
|
Value
|
|
S7.S7CpuStatusUnknown
|
0x00
|
The CPU status is unknown.
|
S7.S7CpuStatusRun
|
0x08
|
The CPU is running.
|
S7.S7CpuStatusStop
|
0x04
|
The CPU is stopped.
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
Security functions
With these functions is possible to know the current protection level, and to set/clear the current session password.
The correct name of the below functions SetSessionPassword and ClearSessionPassword, would have to be Login and Logout to avoid misunderstandings about their scope.
Especially because, if you look at the source code, there is an encoding function that translates the plain password before send it to the PLC.
PASSWORD HACKING IS VERY FAR FROM THE AIM OF THIS PROJECT, MOREOVER YOU NEED TO KNOW THE CORRECT PASSWORD TO MEET THE CPU SECURITY LEVEL.
Detailed information about the protection level can be found in §33.19 of "System Software for S7-300/400 System and Standard Functions".
Function
|
Purpose
|
SetSessionPassword
|
Send the password to the PLC to meet its security level.
|
ClearSessionPassword
|
Clears the password set for the current session (logout).
|
GetProtection
|
Gets the CPU protection level info.
|
SetSessionPassword
Description
Send the password to the PLC to meet its security level.
Declaration
public int SetSessionPassword(string Password);
Parameters
|
Type
|
Dir.
|
|
Password
|
String
|
In
|
8 chars UTF-8 string
|
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
Remarks
A password accepted by a PLC is an 8 chars string, a greater password will be truncated, and a smaller one will be "right space padded".
ClearSessionPassword
Description
Clears the password set for the current session (logout).
Declaration
public int ClearSessionPassword()
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
GetProtection
Description
Gets the CPU protection level info.
Declaration
public int GetProtection(ref S7Protection Protection)
Parameters
|
Type
|
Dir.
|
|
Protection
|
S7Protection
|
Out
|
See below
|
TS7Protection fields
public struct S7Protection
{
public ushort sch_schal;
public ushort sch_par;
public ushort sch_rel;
public ushort bart_sch;
public ushort anl_sch;
};
|
Field Values
|
Values
|
|
sch_schal
|
1, 2, 3
|
Protection level set with the mode selector.
|
sch_par
|
0, 1, 2, 3
|
Password level, 0 : no password
|
sch_rel
|
0, 1, 2, 3
|
Valid protection level of the CPU
|
bart_sch
|
1, 2, 3, 4
|
Mode selector setting (1:RUN, 2:RUN-P, 3:STOP, 4:MRES, 0:undefined or cannot be determined)
|
anl_sch;
|
0, 1, 2
|
Startup switch setting (1:CRST, 2:WRST, 0:undefined, does
not exist of cannot be determined)
|
See also §33.19 of "System Software for S7-300/400 System and Standard Functions"
Return value
- 0 : The function was accomplished with no errors.
- Other values : see the Errors Code List.
Properties/Info Functions
ConnTimeout
int, in/Out – Gets/Sets the connection timeout (in milliseconds) for a telegram.
RecvTimeout
int, in/out – Gets/Sets the receiving timeout (in milliseconds) for a telegram.
SendTimeout
int, in/out – Gets/Sets the sending timeout (in milliseconds) for a telegram.
Connected
bool, out – It’s true if the Client is connected.
PduSizeNegotiated
int, out – Returns the PDU size negotiated.
PduSizeRequested
int, in/out – Gets/Sets the PDU size to be negotiated.
PLCPort
int, in/out – Gets/Sets the connection Port (by default is 102).ExecutionTime
int, out – Returns the last operation execution time in ms.
public int LastError()
Returns the last operation error.
public string ErrorText(int Error)
Returns a textual explanation of Error
public int ExecTime()
Returns the last operation execution time in ms. (compatibility with Snap7.net.cs)
S7 Helper reference
This class allow to read/write an “S7” value into a byte buffer, all new S71200/1500 types are supported.
Read functions are in format:
public static <.NET native Type> Get<S7 Type>At(byte[] Buffer, int Pos)
They extract a <S7 Type> var from the byte buffer starting from the byte number “pos”.
Write functions are in format:
public static void Set<S7 Type>At(byte[] Buffer, int Pos, <.NET native Type> Value)
They insert a .net native type var into the byte buffer starting from the byte number “pos”.
Data access example
Now, just a real example of how to read a S7 struct from a PLC into .NET struct using this class in C# and VB.
Let’s suppose that we make a leak test on an automotive component and that we want to acquire the result of this test.
The data of this test consists of some values (Component serial number, Leak Value etc..) stored in DB 100 as in figure.
Every time a component is tested this struct is filled by the PLC and we want to read it into a .NET struct, picking the fields and adjusting their byte-order (the PLC is Big-Endian, the PC is Little-Endian, so the bytes must be reversed).
This is our C# sample struct:
public struct ComponentResult
{
public String SerialNumber; // Component Serial Number
public int TestResult; // Result code 0:Unknown, 1:Good, 2:Scrap
public double LeakDetected; // Leak value [cc/min]
public DateTime TestDateTime; // Test Timestamp
}
|
And this is the C# sample function that fills the struct. Notice that the outcome of any Client function call should be checked, here is skipped for brevity.
private ComponentResult LeakResult()
{
ComponentResult Result = new ComponentResult();
byte[] Buffer = new byte[26];
// Reads the buffer.
Client.DBRead(100, 0, 26, Buffer);
// Extracts the fields and inserts them into the struct
Result.SerialNumber = S7.GetCharsAt(Buffer, 0, 12);
Result.TestResult = S7.GetIntAt(Buffer, 12);
Result.LeakDetected = S7.GetRealAt(Buffer, 14);
Result.TestDateTime = S7.GetDateTimeAt(Buffer, 18);
return Result;
}
|
The struct
Private Structure ComponentResult
Public SerialNumber As String ' Component Serial Number
Public TestResult As Integer ' Result code 0:Unknown, 1:Good, 2:Scrap
Public LeakDetected As Double ' Leak value [cc/min]
Public TestDateTime As DateTime ' Test Timestamp
End Structure
|
The function
Private Function LeakResult() As ComponentResult
Dim Result As ComponentResult
Dim Buffer(26) As Byte
Client.DBRead(100, 0, 26, Buffer)
Result.SerialNumber = S7.GetCharsAt(Buffer, 0, 12)
Result.TestResult = S7.GetIntAt(Buffer, 12)
Result.LeakDetected = S7.GetRealAt(Buffer, 14)
Result.TestDateTime = S7.GetDateTimeAt(Buffer, 18)
Return Result
End Function
|
Finally, if you put a button and 4 labels in the form of VB demo, with this simple code you can test the mechanism.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim CR As ComponentResult = LeakResult()
Label1.Text = CR.SerialNumber ' It’s already a string
Label2.Text = System.Convert.ToString(CR.TestResult)
Label3.Text = System.Convert.ToString(CR.LeakDetected)
Label4.Text = System.Convert.ToString(CR.TestDateTime)
End Sub
|
S7MultiVar reference
This class allows to fill the S7DataItem[] and performs a ReadMultivar or WriteMultivar without using unsafe code.
The best way to understand the use of this class is analyzing an example.
The process is simple:
- Instantiate the class.
- Add the vars reference (i.e. your buffer) specifying the kind of element that we want read or write.
- Call Read or Write method.
Read example
// Multi Reader Instance specifying Client
S7MultiVar Reader = new S7MultiVar(Client);
// Our buffers
byte[] DB_A = new byte[1024];
byte[] DB_B = new byte[1024];
byte[] DB_C = new byte[1024];
// Our DB number references
int DBNumber_A = 1; // DB1
int DBNumber_B = 1; // DB2
int DBNumber_C = 1; // DB3
// Add Items def. specifying 16 bytes to read starting from 0
Reader.Add(S7Consts.S7AreaDB, S7Consts.S7WLByte, DBNumber_A, 0, 16, ref DB_A);
Reader.Add(S7Consts.S7AreaDB, S7Consts.S7WLByte, DBNumber_B, 0, 16, ref DB_B);
Reader.Add(S7Consts.S7AreaDB, S7Consts.S7WLByte, DBNumber_C, 0, 16, ref DB_C);
// Performs the Read
int Result = Reader.Read();
|
If everything is ok into DB_A, DB_B, DB_C we will find the first 16 bytes of DB1, DB2 and DB3.
Remarks
- Reader.Result[] will contain the single outcome of the items, it’s possible that some items were read and some other not.
- The parameters of Add() are the same of Read/WriteArea, you can read/write non only DB but also E/A/MK/T/C and also bits.
Error codes
Please refer to code of the function ErrorText() for the explanation
errTCPSocketCreation = 0x00000001;
errTCPConnectionTimeout = 0x00000002;
errTCPConnectionFailed = 0x00000003;
errTCPReceiveTimeout = 0x00000004;
errTCPDataReceive = 0x00000005;
errTCPSendTimeout = 0x00000006;
errTCPDataSend = 0x00000007;
errTCPConnectionReset = 0x00000008;
errTCPNotConnected = 0x00000009;
errTCPUnreachableHost = 0x00002751;
errIsoConnect = 0x00010000;
errIsoInvalidPDU = 0x00030000;
errIsoInvalidDataSize = 0x00040000;
errCliNegotiatingPDU = 0x00100000;
errCliInvalidParams = 0x00200000;
errCliJobPending = 0x00300000;
errCliTooManyItems = 0x00400000;
errCliInvalidWordLen = 0x00500000;
errCliPartialDataWritten = 0x00600000;
errCliSizeOverPDU = 0x00700000;
errCliInvalidPlcAnswer = 0x00800000;
errCliAddressOutOfRange = 0x00900000;
errCliInvalidTransportSize = 0x00A00000;
errCliWriteDataSizeMismatch = 0x00B00000;
errCliItemNotAvailable = 0x00C00000;
errCliInvalidValue = 0x00D00000;
errCliCannotStartPLC = 0x00E00000;
errCliAlreadyRun = 0x00F00000;
errCliCannotStopPLC = 0x01000000;
errCliCannotCopyRamToRom = 0x01100000;
errCliCannotCompress = 0x01200000;
errCliAlreadyStop = 0x01300000;
errCliFunNotAvailable = 0x01400000;
errCliUploadSequenceFailed = 0x01500000;
errCliInvalidDataSizeRecvd = 0x01600000;
errCliInvalidBlockType = 0x01700000;
errCliInvalidBlockNumber = 0x01800000;
errCliInvalidBlockSize = 0x01900000;
errCliNeedPassword = 0x01D00000;
errCliInvalidPassword = 0x01E00000;
errCliNoPasswordToSetOrClear = 0x01F00000;
errCliJobTimeout = 0x02000000;
errCliPartialDataRead = 0x02100000;
errCliBufferTooSmall = 0x02200000;
errCliFunctionRefused = 0x02300000;
errCliDestroying = 0x02400000;
errCliInvalidParamNumber = 0x02500000;
errCliCannotChangeParam = 0x02600000;
errCliFunctionNotImplemented = 0x02700000;