rllib
1
|
#include <rlsiemenstcp.h>
Classes | |
struct | FA |
struct | FH |
struct | IH |
struct | WA |
struct | WH |
Public Types | |
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, LOGO = 7 } |
enum | SiemensFunctionCodes { WriteBit = 1, WriteByte = 2 } |
Public Types inherited from rlSocket | |
enum | SocketEnum { SOCKET_ERR = -1, SETSOCKOPT_ERR = -2, LISTEN_ERR = -3, ACCEPT_ERR = -4, INET_ADDR_ERR = -5, CONNECT_ERR = -6, PORT_ERR = -7 } |
Public Member Functions | |
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 () |
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) |
Public Member Functions inherited from rlSocket | |
rlSocket (const char *adr, int port, int active) | |
rlSocket (int socket) | |
virtual | ~rlSocket () |
void | setAdr (const char *adr) |
void | setPort (int port) |
int | getPort () |
void | setActive (int active) |
int | read (void *buf, int len, int timeout=0) |
int | readStr (char *buf, int len, int timeout=0) |
int | readHttpHeader (rlString *header, int timeout=0) |
int | write (const void *buf, int len) |
int | printf (const char *format,...) |
int | connect () |
int | disconnect () |
int | select (int timeout=0) |
int | isConnected () |
int | setIPVersion (int version) |
int | getIPVersion () |
int | sendProcessViewBrowserButtonEvent (int id) |
int | rlGetsockopt (int level, int optname) |
int | rlSetsockopt (int level, int optname) |
int | readHttpContentLength (int timeout) |
Private Member Functions | |
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) |
Private Attributes | |
WH | wh |
WA | wa |
FH | fh |
FA | fa |
IH | ih |
int | function |
int | rack_slot |
int | plc_type |
int | fetch_write |
unsigned char | pdu [2048] |
int | use_cb |
unsigned char | cb [22] |
Additional Inherited Members | |
Static Public Member Functions inherited from rlSocket | |
static int | rlGetsockopt (int sockfd, int level, int optname, void *optval, int *optlen) |
static int | rlSetsockopt (int sockfd, int level, int optname, const void *optval, int optlen) |
Public Attributes inherited from rlSocket | |
int | s |
unsigned char | sockaddr [16+48] |
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:
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
Definition at line 130 of file rlsiemenstcp.h.
enum rlSiemensTCP::ORG |
Enumerator | |
---|---|
ORG_DB | |
ORG_M | |
ORG_E | |
ORG_A | |
ORG_PEPA | |
ORG_Z | |
ORG_T |
Definition at line 133 of file rlsiemenstcp.h.
Enumerator | |
---|---|
ANY_SIEMENS_COMPATIBLE_PLC | |
S7_200 | |
S7_300 | |
S7_400 | |
S5 | |
RACK_SLOT | |
S7_1200 | |
LOGO |
Definition at line 143 of file rlsiemenstcp.h.
Enumerator | |
---|---|
WriteBit | |
WriteByte |
Definition at line 154 of file rlsiemenstcp.h.
rlSiemensTCP::rlSiemensTCP | ( | const char * | adr, |
int | _plc_type = rlSiemensTCP::ANY_SIEMENS_COMPATIBLE_PLC , |
||
int | _fetch_write = 1 , |
||
int | function = -1 , |
||
int | rack_slot = -1 |
||
) |
Definition at line 31 of file rlsiemenstcp.cpp.
|
virtual |
Definition at line 45 of file rlsiemenstcp.cpp.
|
private |
Definition at line 71 of file rlsiemenstcp.cpp.
int rlSiemensTCP::fetch | ( | int | org, |
int | dbnr, | ||
int | start_adr, | ||
int | length, | ||
unsigned char * | buf | ||
) |
Definition at line 434 of file rlsiemenstcp.cpp.
int rlSiemensTCP::getConnectBlock | ( | unsigned char * | connect_block | ) |
Definition at line 65 of file rlsiemenstcp.cpp.
int rlSiemensTCP::getDefaultConnectBlock | ( | unsigned char * | connect_block | ) |
Definition at line 50 of file rlsiemenstcp.cpp.
|
private |
Definition at line 181 of file rlsiemenstcp.cpp.
|
private |
Definition at line 561 of file rlsiemenstcp.cpp.
int rlSiemensTCP::setConnectBlock | ( | const unsigned char * | connect_block | ) |
Definition at line 58 of file rlsiemenstcp.cpp.
int rlSiemensTCP::write | ( | int | org, |
int | dbnr, | ||
int | start_adr, | ||
int | length, | ||
const unsigned char * | buf, | ||
int | function = WriteByte |
||
) |
Definition at line 212 of file rlsiemenstcp.cpp.
|
private |
Definition at line 367 of file rlsiemenstcp.cpp.
|
private |
Definition at line 403 of file rlsiemenstcp.cpp.
|
private |
Definition at line 607 of file rlsiemenstcp.cpp.
|
private |
Definition at line 252 of file rlsiemenstcp.h.
|
private |
Definition at line 245 of file rlsiemenstcp.h.
|
private |
Definition at line 249 of file rlsiemenstcp.h.
|
private |
Definition at line 244 of file rlsiemenstcp.h.
|
private |
Definition at line 247 of file rlsiemenstcp.h.
|
private |
Definition at line 246 of file rlsiemenstcp.h.
|
private |
Definition at line 250 of file rlsiemenstcp.h.
|
private |
Definition at line 248 of file rlsiemenstcp.h.
|
private |
Definition at line 247 of file rlsiemenstcp.h.
|
private |
Definition at line 251 of file rlsiemenstcp.h.
|
private |
Definition at line 243 of file rlsiemenstcp.h.
|
private |
Definition at line 242 of file rlsiemenstcp.h.