mirror of
https://gitee.com/js-yhsec/energy_storage.git
synced 2026-05-28 03:09:24 +08:00
256 lines
9.4 KiB
C++
256 lines
9.4 KiB
C++
/***************************************************************************
|
|
rlsiemenstcp.h - description
|
|
-------------------
|
|
begin : Mon Mar 08 2004
|
|
copyright : (C) 2004 by R. Lehrig
|
|
email : lehrig@t-online.de
|
|
|
|
S7_200 update : Wed Mar 21 2007
|
|
copyright : (C) 2007 by Aljosa Merljak
|
|
Email : aljosa.merljak@datapan.si
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This library is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as *
|
|
* published by the Free Software Foundation *
|
|
* *
|
|
***************************************************************************/
|
|
#ifndef _RL_SIEMENS_TCP_H_
|
|
#define _RL_SIEMENS_TCP_H_
|
|
|
|
#include "rldefine.h"
|
|
#include "rlsocket.h"
|
|
|
|
/*! <pre>
|
|
class for communication with Siemens PLC's via TCP
|
|
|
|
(1) There is the old Fetch/Write protocol from the old S5 PLC (fetch_write=1).
|
|
|
|
(2) And there is the current Siemens PLC protocol introduced with the S7 series of PLC (fetch_write=0).
|
|
|
|
According to
|
|
http://www.ietf.org/rfc/rfc0905.txt
|
|
the client will send a connection request to the PLC after it has establisched a TCP connection().
|
|
|
|
Here is a example connect_block for a Siemens S7 PLC (CBxx in hex):
|
|
CB00= 3, ISO_HEADER_VERSION
|
|
CB01= 0, ISO_HEADER_RESERVED
|
|
CB02= 0, ISO_HEADER_LENGHT_HIGH
|
|
CB03=16, ISO_HEADER_LENGHT_LOW = 22 Byte (hex 16)
|
|
CB04=11, Length Indicator Field = 17 dec = 22 byte_total_length - 1 byte_length_indicator - 4 byte_ISO_HEADER
|
|
CB05=E0, Connection Request Code (Bits 8-5) 1110=E, Initial Credit Allocation (Bits 4-1) Class 0
|
|
CB06= 0, DESTINATION-REF-HIGH
|
|
CB07= 0, DESTINATION-REF-LOW
|
|
CB08= 0, SOURCE-REF-HIGH
|
|
CB09= 1, SOURCE-REF-LOW
|
|
CB10= 0, Class and Option
|
|
CB11=C1, Identifier: Calling TSAP will follow
|
|
CB12= 2, Parameter Length, 2 byte will follow
|
|
CB13= 1, Remote TSAP, free to choose on client side (1=PG,2=OP,3=Step7Basic) suggested
|
|
CB14= 0, Remote TSAP, free to choose on client side (upper_3_bit_is_rack / lower_5_bit_is_slot) suggested
|
|
CB15=C2, Identifier: Called TSAP will follow
|
|
CB16= 2, Parameter Length, 2 byte will follow
|
|
CB17= 1, Local TSAP, set within Step7 = 1 (1=PG,2=OP,3=Step7Basic)
|
|
CB18= 0, Local TSAP, set within Step7 = 0...connectionN (upper_3_bit_is_rack / lower_5_bit_is_slot)
|
|
CB19=C0, Identifier: Maximum TPDU size will follow
|
|
CB20= 1, Parameter Length, 1 byte will follow
|
|
CB21= 9, max 512 octets
|
|
|
|
For the different PLC types the connect_block looks as follows:
|
|
s7_200 = {3,0,0,16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,'M','W',0xC2,2,'M','W',0xC0,1,9}
|
|
s7_300 = {3,0,0,16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2, 1,0 ,0xC2,2, 1,2 ,0xC0,1,9} on S7_300 slot of cpu is always 2
|
|
s7_400 = {3,0,0,16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2, 1,0 ,0xC2,2, 1,3 ,0xC0,1,9} on S7_400 slot of cpu is always 3
|
|
s7_1200 = {3,0,0,16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2, 1,0 ,0xC2,2, 1,0 ,0xC0,1,9} slot may be 0 || 1 and TSAP 03.01 || 10.00
|
|
s7_logo = {3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2, 2,0 ,0xC2,2, 2,0 ,0xC0,1,9}
|
|
For S7_200 and S7_1200 read: (only symbolic access to DB1)
|
|
http://support.automation.siemens.com/WW/llisapi.dll?func=cslib.csinfo&lang=en&objid=21601611&caller=view
|
|
|
|
According to the Remote TSAP Siemens makes the following statement:
|
|
######################################################################################
|
|
Remote TSAP (Remote Transport Service Access Point, entfernter Dienstzugangspunkt)
|
|
The representation is the same as with the Local TSAP,
|
|
but the second byte has another meaning:
|
|
- first Byte: contains a device id (allowed 02 or 03)
|
|
02 OS (Operating Station Bedienen und Beobachten)
|
|
03 other
|
|
suggested: 02
|
|
- second Byte: contains the adressing within the SIMATIC S7-CPU,
|
|
divided in:
|
|
Bit 7 ... 5 Rack (Subsystem) of the S7-CPU
|
|
Bit 4 ... 0 Slot of the S7-CPU
|
|
Hint: It is suggested to choose the same settings for Byte 1 in Remote and Local TSAP
|
|
######################################################################################
|
|
|
|
When you use our rlSiemensTCP class you can do it as follows:
|
|
|
|
unsigned char cb[22];
|
|
rlSiemensTCP *plc = new rlSiemensTCP(adr);
|
|
plc->getDefaultConnectBlock(cb);
|
|
cb[13] = 1; // set 1 Byte of Remote TSAP
|
|
cb[14] = 0; // set 2 Byte of Remote TSAP
|
|
cb[17] = 1; // set Local TSAP of the PLC to the
|
|
cb[18] = 0; // configuration done within Step 7
|
|
plc->setConnectBlock(cb);
|
|
|
|
Now you can read/write the PLC.
|
|
|
|
The following matrix shows some combinations:
|
|
--------------------------------------------
|
|
| CB13 CB14 CB17 CB18
|
|
--------------------------------------------
|
|
S7_200 | 'M' 'W' 'M' 'W'
|
|
--------------------------------------------
|
|
S7_300 | 1 0 1 2
|
|
--------------------------------------------
|
|
S7_400 | 1 0 1 3
|
|
--------------------------------------------
|
|
S7_1200 | 1 0 1 0
|
|
--------------------------------------------
|
|
S7_logo 0BA7 | 2 0 2 0
|
|
--------------------------------------------
|
|
|
|
CB17 = (1=PG,2=OP,3=Step7Basic)
|
|
CB18 = (upper_3_bit_is_rack / lower_5_bit_is_slot)
|
|
Thus the above would be:
|
|
A TSAP within Step 7 of 10.00 results in: cb[17] = PG; cb[18] = 0; // rack=0 slot=0
|
|
A TSAP within Step 7 of 10.01 results in: cb[17] = PG; cb[18] = 1; // rack=0 slot=1
|
|
A TSAP within Step 7 of 10.02 results in: cb[17] = PG; cb[18] = 2; // rack=0 slot=2
|
|
A TSAP within Step 7 of 10.03 results in: cb[17] = PG; cb[18] = 3; // rack=0 slot=3
|
|
|
|
You may use rlSiemensTCP with the individual plc_type for conveniance.
|
|
But you can set the whole connect_block and use ANY_SIEMENS_COMPATIBLE_PLC.
|
|
|
|
Please use Wireshark or tcpdump if the settings of the above matrix do not work for you.
|
|
Send us your results.
|
|
|
|
PS: Still wondering about 'M' 'W' on S7-200
|
|
</pre> */
|
|
class rlSiemensTCP : public rlSocket
|
|
{
|
|
public:
|
|
enum ORG
|
|
{
|
|
ORG_DB = 1,
|
|
ORG_M = 2,
|
|
ORG_E = 3,
|
|
ORG_A = 4,
|
|
ORG_PEPA = 5,
|
|
ORG_Z = 6,
|
|
ORG_T = 7
|
|
};
|
|
enum PLC_TYPE
|
|
{
|
|
ANY_SIEMENS_COMPATIBLE_PLC = 1000,
|
|
S7_200 = 1,
|
|
S7_300 = 2,
|
|
S7_400 = 3,
|
|
S5 = 4,
|
|
RACK_SLOT = 5,
|
|
S7_1200 = 6, // patch from user slammera from our forum (8 Nov 2012)
|
|
LOGO = 7 // LOGO! 0BA7, according to jjmg_engenharia from our forum (3 Sep 2013)
|
|
};
|
|
enum SiemensFunctionCodes
|
|
{
|
|
WriteBit = 1,
|
|
WriteByte = 2
|
|
};
|
|
rlSiemensTCP(const char *adr, int _plc_type=rlSiemensTCP::ANY_SIEMENS_COMPATIBLE_PLC, int _fetch_write = 1, int function = -1, int rack_slot = -1);
|
|
virtual ~rlSiemensTCP();
|
|
/*! <pre>
|
|
</pre> */
|
|
int getDefaultConnectBlock(unsigned char *connect_block);
|
|
int setConnectBlock(const unsigned char *connect_block);
|
|
int getConnectBlock(unsigned char *connect_block);
|
|
int write(int org, int dbnr, int start_adr, int length, const unsigned char *buf, int function=WriteByte);
|
|
int fetch(int org, int dbnr, int start_adr, int length, unsigned char *buf);
|
|
private:
|
|
void doConnect();
|
|
int read_iso(unsigned char *buf);
|
|
int write_iso(unsigned char *buf, int len);
|
|
int getOrg(int org);
|
|
int write_bit(int& i, int org, int dbnr, int start_adr, int len, const unsigned char *buf);
|
|
int write_byte(int& i, int org, int dbnr, int start_adr, int length, const unsigned char *buf);
|
|
typedef struct
|
|
{
|
|
unsigned char version;
|
|
unsigned char reserved;
|
|
unsigned char length_high;
|
|
unsigned char length_low;
|
|
}IH; // iso header
|
|
typedef struct
|
|
{
|
|
unsigned char ident[2];
|
|
unsigned char header_len;
|
|
unsigned char ident_op_code;
|
|
unsigned char op_code_len;
|
|
unsigned char op_code;
|
|
unsigned char ident_org_block;
|
|
unsigned char len_org_block;
|
|
unsigned char org_block;
|
|
unsigned char dbnr;
|
|
unsigned char start_adr[2];
|
|
unsigned char len[2];
|
|
unsigned char spare1;
|
|
unsigned char spare1_len;
|
|
}WH; // write header
|
|
typedef struct
|
|
{
|
|
unsigned char ident[2];
|
|
unsigned char header_len;
|
|
unsigned char ident_op_code;
|
|
unsigned char op_code_len;
|
|
unsigned char op_code;
|
|
unsigned char ack_block;
|
|
unsigned char ack_block_len;
|
|
unsigned char error_block;
|
|
unsigned char spare1;
|
|
unsigned char spare1_len;
|
|
unsigned char spare2[5];
|
|
}WA; // write ack
|
|
typedef struct
|
|
{
|
|
unsigned char ident[2];
|
|
unsigned char header_len;
|
|
unsigned char ident_op_code;
|
|
unsigned char op_code_len;
|
|
unsigned char op_code;
|
|
unsigned char ident_org_block;
|
|
unsigned char len_org_block;
|
|
unsigned char org_block;
|
|
unsigned char dbnr;
|
|
unsigned char start_adr[2];
|
|
unsigned char len[2];
|
|
unsigned char spare1;
|
|
unsigned char spare1_len;
|
|
}FH; // fetch header
|
|
typedef struct
|
|
{
|
|
unsigned char ident[2];
|
|
unsigned char header_len;
|
|
unsigned char ident_op_code;
|
|
unsigned char op_code_len;
|
|
unsigned char op_code;
|
|
unsigned char ack_block;
|
|
unsigned char ack_block_len;
|
|
unsigned char error_block;
|
|
unsigned char spare1;
|
|
unsigned char spare1_len;
|
|
unsigned char spare2[5];
|
|
}FA; // fetch ack
|
|
WH wh;
|
|
WA wa;
|
|
FH fh;
|
|
FA fa;
|
|
IH ih;
|
|
int function, rack_slot;
|
|
int plc_type;
|
|
int fetch_write;
|
|
unsigned char pdu[2048];
|
|
int use_cb;
|
|
unsigned char cb[22];
|
|
};
|
|
|
|
#endif
|